summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CONTRIBUTE26
-rwxr-xr-xadmin/diff-tar-files4
-rw-r--r--admin/make-tarball.txt33
-rw-r--r--lib-src/Makefile.in4
-rw-r--r--lisp/tab-bar.el7
-rw-r--r--src/alloc.c20
-rw-r--r--src/comp.c18
-rw-r--r--src/comp.h10
-rw-r--r--src/data.c10
-rw-r--r--src/eval.c23
-rw-r--r--src/fileio.c4
-rw-r--r--src/lisp.h16
-rw-r--r--src/lread.c12
-rw-r--r--src/pdumper.c40
-rw-r--r--test/lisp/tab-bar-tests.el51
15 files changed, 183 insertions, 95 deletions
diff --git a/CONTRIBUTE b/CONTRIBUTE
index 5740004637b..7c3421ed75a 100644
--- a/CONTRIBUTE
+++ b/CONTRIBUTE
@@ -185,20 +185,26 @@ ChangeLog file, where they can be corrected. It saves time to get
them right the first time, so here are guidelines for formatting them:
- Start with a single unindented summary line explaining the change;
- do not end this line with a period. If that line starts with a
- semicolon and a space "; ", the commit message will be ignored when
- generating the ChangeLog file. Use this for minor commits that do
- not need separate ChangeLog entries, such as changes in etc/NEWS.
+ do not end this line with a period. If possible, try to keep the
+ summary line to 50 characters or fewer; this is for compatibility
+ with certain Git commands that print that line in width-constrained
+ contexts.
-- After the summary line, there should be an empty line, then
- unindented ChangeLog entries.
+ If the summary line starts with a semicolon and a space "; ", the
+ commit message will be ignored when generating the ChangeLog file.
+ Use this for minor commits that do not need separate ChangeLog
+ entries, such as changes in etc/NEWS.
+
+- After the summary line, there should be an empty line.
+
+- Unindented ChangeLog entries normally come next. However, if the
+ commit couldn't be properly summarized in the brief summary line,
+ you can put a paragraph (after the empty line and before the
+ individual ChangeLog entries) that further describes the commit.
- Limit lines in commit messages to 78 characters, unless they consist
of a single word of at most 140 characters; this is enforced by a
- commit hook. It's nicer to limit the summary line to 50 characters;
- this isn't enforced. If the change can't be summarized so briefly,
- add a paragraph after the empty line and before the individual file
- descriptions.
+ commit hook.
- If only a single file is changed, the summary line can be the normal
file first line (starting with the asterisk). Then there is no
diff --git a/admin/diff-tar-files b/admin/diff-tar-files
index cdcc512ae6b..2fe15401d0d 100755
--- a/admin/diff-tar-files
+++ b/admin/diff-tar-files
@@ -35,7 +35,7 @@ old_tmp=/tmp/old.$$
new_tmp=/tmp/new.$$
trap "rm -f $old_tmp $new_tmp; exit 1" 1 2 15
-tar tzf "$old_tar" | sed -e 's,^[^/]*,,' | sort > $old_tmp
-tar tzf "$new_tar" | sed -e 's,^[^/]*,,' | sort > $new_tmp
+tar tf "$old_tar" | sed -e 's,^[^/]*,,' | sort > $old_tmp
+tar tf "$new_tar" | sed -e 's,^[^/]*,,' | sort > $new_tmp
diff -u $old_tmp $new_tmp
rm -f $new_tmp $old_tmp
diff --git a/admin/make-tarball.txt b/admin/make-tarball.txt
index 22276080c5d..872cb00ca28 100644
--- a/admin/make-tarball.txt
+++ b/admin/make-tarball.txt
@@ -5,7 +5,7 @@ Instructions to create pretest or release tarballs. -*- coding: utf-8 -*-
Steps to take before starting on the first pretest in any release sequence:
-0. The release branch (e.g. emacs-26) should already have been made
+0. The release branch (e.g. emacs-28) should already have been made
and you should use it for all that follows. Diffs from this
branch should be going to the emacs-diffs mailing list.
@@ -14,12 +14,13 @@ Steps to take before starting on the first pretest in any release sequence:
2. Consider increasing the value of the variable
'customize-changed-options-previous-release' in cus-edit.el to
- refer to a newer version of Emacs. (This is probably needed only
- when preparing the first pretest for a major Emacs release.)
+ refer to a newer version of Emacs. (This is now done when cutting
+ the release branch, see admin/release-branch.txt.)
Commit cus-edit.el if changed.
3. Remove any old pretests from https://alpha.gnu.org/gnu/emacs/pretest.
You can use 'gnupload --delete' (see below for more gnupload details).
+ (We currently don't bother with this.)
General steps (for each step, check for possible errors):
@@ -89,7 +90,7 @@ General steps (for each step, check for possible errors):
admin/release-process must be completed.
Set the version number to that of the actual release (commit in
- one, as described above). Pick a date about a week from now when
+ one, as described above). Pick a date about a week from now when
you intend to make the release. Use M-x add-release-logs to add
entries to etc/HISTORY and the ChangeLog file. It's best not to
commit these files until the release is actually made. Merge the
@@ -163,8 +164,15 @@ General steps (for each step, check for possible errors):
If this is the first pretest of a major release, just comparing
with the previous release may overlook many new files. You can try
- something like 'find . | sort' in a clean repository, and compare the
- results against the new tar contents.
+ something like 'find . | sort' in a clean repository, and
+ compare the results against the new tar contents. Another
+ alternative is using something like:
+
+ tar cf - emacs-NEW | tar t -C /tmp | grep -Ev "\.(o|d)$" | sort
+
+ Where emacs-NEW is the directory containing your clean repository.
+ The output of this command might be easier to compare to the
+ tarball than the one you get from find.
7. tar -xf emacs-NEW.tar; cd emacs-NEW
./configure --prefix=/tmp/emacs && make check && make install
@@ -194,6 +202,14 @@ General steps (for each step, check for possible errors):
git tag -a TAG -m "Emacs TAG" SHA1
git push --tags
+ In the past, we were not always consistent with the annotation
+ (i.e. -m "Emacs TAG"). The preferred format is like this for a
+ pretest, release candidate and final release:
+
+ git tag -a emacs-28.0.90 -m "Emacs 28.0.90 pretest"
+ git tag -a emacs-28.1-rc1 -m "Emacs 28.1 RC1"
+ git tag -a emacs-28.1 -m "Emacs 28.1 release"
+
9. Decide what compression schemes to offer.
For a release, at least gz and xz:
gzip --best --no-name -c emacs-NEW.tar > emacs-NEW.tar.gz
@@ -256,6 +272,11 @@ General steps (for each step, check for possible errors):
because replies that invariably are not announcements also get
sent out as if they were.)
+ To create the included SHA1 and SHA256 checksums, run:
+
+ sha1sum emacs-NEW.tar.xz
+ sha256sum emacs-NEW.tar.xz
+
12. After a release, update the Emacs pages as described below.
13. Bump the Emacs version on the release branch.
diff --git a/lib-src/Makefile.in b/lib-src/Makefile.in
index d062e78366f..c07b678839c 100644
--- a/lib-src/Makefile.in
+++ b/lib-src/Makefile.in
@@ -195,6 +195,8 @@ LIB_CLOCK_GETTIME = @LIB_CLOCK_GETTIME@
LIB_GETRANDOM = @LIB_GETRANDOM@
## Whatever libraries are needed for euidaccess
LIB_EACCESS=@LIB_EACCESS@
+## Libraries needed for file_has_acl
+LIB_HAS_ACL=@LIB_HAS_ACL@
## empty or -lwsock2 for MinGW
LIB_WSOCK32=@LIB_WSOCK32@
@@ -418,7 +420,7 @@ pop.o: ${srcdir}/pop.c ${srcdir}/pop.h ${srcdir}/../lib/min-max.h $(config_h)
emacsclient${EXEEXT}: ${srcdir}/emacsclient.c $(NTLIB) $(config_h)
$(AM_V_CCLD)$(CC) ${ALL_CFLAGS} $< \
$(NTLIB) $(LOADLIBES) \
- $(LIB_WSOCK32) $(LIB_EACCESS) $(LIBS_ECLIENT) -o $@
+ $(LIB_WSOCK32) $(LIB_EACCESS) $(LIB_HAS_ACL) $(LIBS_ECLIENT) -o $@
emacsclientw${EXEEXT}: ${srcdir}/emacsclient.c $(NTLIB) $(CLIENTRES) $(config_h)
$(AM_V_CCLD)$(CC) ${ALL_CFLAGS} $(CLIENTRES) -mwindows $< \
diff --git a/lisp/tab-bar.el b/lisp/tab-bar.el
index 656cb878e3e..7a5221d83ab 100644
--- a/lisp/tab-bar.el
+++ b/lisp/tab-bar.el
@@ -1586,18 +1586,17 @@ happens interactively)."
(let* ((tabs (funcall tab-bar-tabs-function))
(current-index (tab-bar--current-tab-index tabs))
(keep-index (if (integerp tab-number)
- (1- (max 0 (min tab-number (length tabs))))
+ (1- (max 1 (min tab-number (length tabs))))
current-index))
- (keep-tab (nth keep-index tabs))
(index 0))
- (when keep-tab
+ (when (nth keep-index tabs)
(unless (eq keep-index current-index)
(tab-bar-select-tab (1+ keep-index))
(setq tabs (funcall tab-bar-tabs-function)))
(dolist (tab tabs)
- (unless (or (eq tab keep-tab)
+ (unless (or (eq index keep-index)
(run-hook-with-args-until-success
'tab-bar-tab-prevent-close-functions tab
;; `last-tab-p' logically can't ever be true
diff --git a/src/alloc.c b/src/alloc.c
index f8908c91dba..55c30847bbf 100644
--- a/src/alloc.c
+++ b/src/alloc.c
@@ -3160,26 +3160,26 @@ cleanup_vector (struct Lisp_Vector *vector)
module_finalize_function (function);
}
#endif
- else if (NATIVE_COMP_FLAG
- && PSEUDOVECTOR_TYPEP (&vector->header, PVEC_NATIVE_COMP_UNIT))
+#ifdef HAVE_NATIVE_COMP
+ else if (PSEUDOVECTOR_TYPEP (&vector->header, PVEC_NATIVE_COMP_UNIT))
{
struct Lisp_Native_Comp_Unit *cu =
PSEUDOVEC_STRUCT (vector, Lisp_Native_Comp_Unit);
unload_comp_unit (cu);
}
- else if (NATIVE_COMP_FLAG
- && PSEUDOVECTOR_TYPEP (&vector->header, PVEC_SUBR))
+ else if (PSEUDOVECTOR_TYPEP (&vector->header, PVEC_SUBR))
{
struct Lisp_Subr *subr =
PSEUDOVEC_STRUCT (vector, Lisp_Subr);
- if (!NILP (subr->native_comp_u[0]))
+ if (!NILP (subr->native_comp_u))
{
/* FIXME Alternative and non invasive solution to this
cast? */
xfree ((char *)subr->symbol_name);
- xfree (subr->native_c_name[0]);
+ xfree (subr->native_c_name);
}
}
+#endif
}
/* Reclaim space used by unmarked vectors. */
@@ -6785,15 +6785,17 @@ mark_object (Lisp_Object arg)
break;
case PVEC_SUBR:
+#ifdef HAVE_NATIVE_COMP
if (SUBR_NATIVE_COMPILEDP (obj))
{
set_vector_marked (ptr);
struct Lisp_Subr *subr = XSUBR (obj);
mark_object (subr->native_intspec);
- mark_object (subr->native_comp_u[0]);
- mark_object (subr->lambda_list[0]);
- mark_object (subr->type[0]);
+ mark_object (subr->native_comp_u);
+ mark_object (subr->lambda_list);
+ mark_object (subr->type);
}
+#endif
break;
case PVEC_FREE:
diff --git a/src/comp.c b/src/comp.c
index 7bb160e4f0a..fb9b1a5a2d8 100644
--- a/src/comp.c
+++ b/src/comp.c
@@ -5136,21 +5136,29 @@ make_subr (Lisp_Object symbol_name, Lisp_Object minarg, Lisp_Object maxarg,
if (CONSP (minarg))
{
/* Dynamic code. */
- x->s.lambda_list[0] = maxarg;
+#ifdef HAVE_NATIVE_COMP
+ x->s.lambda_list = maxarg;
+#endif
maxarg = XCDR (minarg);
minarg = XCAR (minarg);
}
else
- x->s.lambda_list[0] = Qnil;
+ {
+#ifdef HAVE_NATIVE_COMP
+ x->s.lambda_list = Qnil;
+#endif
+ }
x->s.function.a0 = func;
x->s.min_args = XFIXNUM (minarg);
x->s.max_args = FIXNUMP (maxarg) ? XFIXNUM (maxarg) : MANY;
x->s.symbol_name = xstrdup (SSDATA (symbol_name));
x->s.native_intspec = intspec;
x->s.doc = XFIXNUM (doc_idx);
- x->s.native_comp_u[0] = comp_u;
- x->s.native_c_name[0] = xstrdup (SSDATA (c_name));
- x->s.type[0] = type;
+#ifdef HAVE_NATIVE_COMP
+ x->s.native_comp_u = comp_u;
+ x->s.native_c_name = xstrdup (SSDATA (c_name));
+ x->s.type = type;
+#endif
Lisp_Object tem;
XSETSUBR (tem, &x->s);
diff --git a/src/comp.h b/src/comp.h
index c4af4193d0b..96bb52a14bc 100644
--- a/src/comp.h
+++ b/src/comp.h
@@ -20,16 +20,6 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
#ifndef COMP_H
#define COMP_H
-/* To keep ifdefs under control. */
-enum {
- NATIVE_COMP_FLAG =
-#ifdef HAVE_NATIVE_COMP
- 1
-#else
- 0
-#endif
-};
-
#include <dynlib.h>
struct Lisp_Native_Comp_Unit
diff --git a/src/data.c b/src/data.c
index 0d3376f0903..b2c395831ae 100644
--- a/src/data.c
+++ b/src/data.c
@@ -891,9 +891,11 @@ function or t otherwise. */)
{
CHECK_SUBR (subr);
- return SUBR_NATIVE_COMPILED_DYNP (subr)
- ? XSUBR (subr)->lambda_list[0]
- : Qt;
+#ifdef HAVE_NATIVE_COMP
+ if (SUBR_NATIVE_COMPILED_DYNP (subr))
+ return XSUBR (subr)->lambda_list;
+#endif
+ return Qt;
}
DEFUN ("subr-type", Fsubr_type,
@@ -917,7 +919,7 @@ DEFUN ("subr-native-comp-unit", Fsubr_native_comp_unit,
(Lisp_Object subr)
{
CHECK_SUBR (subr);
- return XSUBR (subr)->native_comp_u[0];
+ return XSUBR (subr)->native_comp_u;
}
DEFUN ("native-comp-unit-file", Fnative_comp_unit_file,
diff --git a/src/eval.c b/src/eval.c
index 94ad0607732..fe29564aa2d 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -220,17 +220,14 @@ void
init_eval_once (void)
{
/* Don't forget to update docs (lispref node "Local Variables"). */
- if (!NATIVE_COMP_FLAG)
- {
- max_specpdl_size = 1800; /* See bug#46818. */
- max_lisp_eval_depth = 800;
- }
- else
- {
- /* Original values increased for comp.el. */
- max_specpdl_size = 2500;
- max_lisp_eval_depth = 1600;
- }
+#ifndef HAVE_NATIVE_COMP
+ max_specpdl_size = 1800; /* See bug#46818. */
+ max_lisp_eval_depth = 800;
+#else
+ /* Original values increased for comp.el. */
+ max_specpdl_size = 2500;
+ max_lisp_eval_depth = 1600;
+#endif
Vrun_hooks = Qnil;
pdumper_do_now_and_after_load (init_eval_once_for_pdumper);
}
@@ -3278,11 +3275,13 @@ funcall_lambda (Lisp_Object fun, ptrdiff_t nargs,
else if (MODULE_FUNCTIONP (fun))
return funcall_module (fun, nargs, arg_vector);
#endif
+#ifdef HAVE_NATIVE_COMP
else if (SUBR_NATIVE_COMPILED_DYNP (fun))
{
- syms_left = XSUBR (fun)->lambda_list[0];
+ syms_left = XSUBR (fun)->lambda_list;
lexenv = Qnil;
}
+#endif
else
emacs_abort ();
diff --git a/src/fileio.c b/src/fileio.c
index 859b30564aa..12ece586b83 100644
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -2386,7 +2386,9 @@ permissions. */)
if (!NILP (keep_time))
{
- struct timespec ts[] = { get_stat_atime (&st), get_stat_mtime (&st) };
+ struct timespec ts[2];
+ ts[0] = get_stat_atime (&st);
+ ts[1] = get_stat_mtime (&st);
if (futimens (ofd, ts) != 0)
xsignal2 (Qfile_date_error,
build_string ("Cannot set file date"), newname);
diff --git a/src/lisp.h b/src/lisp.h
index 19caba40014..242156bbcb8 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -2091,10 +2091,12 @@ struct Lisp_Subr
Lisp_Object native_intspec;
};
EMACS_INT doc;
- Lisp_Object native_comp_u[NATIVE_COMP_FLAG];
- char *native_c_name[NATIVE_COMP_FLAG];
- Lisp_Object lambda_list[NATIVE_COMP_FLAG];
- Lisp_Object type[NATIVE_COMP_FLAG];
+#ifdef HAVE_NATIVE_COMP
+ Lisp_Object native_comp_u;
+ char *native_c_name;
+ Lisp_Object lambda_list;
+ Lisp_Object type;
+#endif
} GCALIGNED_STRUCT;
union Aligned_Lisp_Subr
{
@@ -4786,19 +4788,19 @@ extern char *emacs_root_dir (void);
INLINE bool
SUBR_NATIVE_COMPILEDP (Lisp_Object a)
{
- return SUBRP (a) && !NILP (XSUBR (a)->native_comp_u[0]);
+ return SUBRP (a) && !NILP (XSUBR (a)->native_comp_u);
}
INLINE bool
SUBR_NATIVE_COMPILED_DYNP (Lisp_Object a)
{
- return SUBR_NATIVE_COMPILEDP (a) && !NILP (XSUBR (a)->lambda_list[0]);
+ return SUBR_NATIVE_COMPILEDP (a) && !NILP (XSUBR (a)->lambda_list);
}
INLINE Lisp_Object
SUBR_TYPE (Lisp_Object a)
{
- return XSUBR (a)->type[0];
+ return XSUBR (a)->type;
}
INLINE struct Lisp_Native_Comp_Unit *
diff --git a/src/lread.c b/src/lread.c
index 2e63ec48912..5a2f1bc54e5 100644
--- a/src/lread.c
+++ b/src/lread.c
@@ -1279,7 +1279,10 @@ Return t if the file exists and loads successfully. */)
|| suffix_p (file, MODULES_SECONDARY_SUFFIX)
#endif
#endif
- || (NATIVE_COMP_FLAG && suffix_p (file, NATIVE_ELISP_SUFFIX)))
+#ifdef HAVE_NATIVE_COMP
+ || suffix_p (file, NATIVE_ELISP_SUFFIX)
+#endif
+ )
must_suffix = Qnil;
/* Don't insist on adding a suffix
if the argument includes a directory name. */
@@ -1359,8 +1362,11 @@ Return t if the file exists and loads successfully. */)
bool is_module = false;
#endif
- bool is_native_elisp =
- NATIVE_COMP_FLAG && suffix_p (found, NATIVE_ELISP_SUFFIX) ? true : false;
+#ifdef HAVE_NATIVE_COMP
+ bool is_native_elisp = suffix_p (found, NATIVE_ELISP_SUFFIX);
+#else
+ bool is_native_elisp = false;
+#endif
/* Check if we're stuck in a recursive load cycle.
diff --git a/src/pdumper.c b/src/pdumper.c
index 9eff5c48d09..02956aa7cec 100644
--- a/src/pdumper.c
+++ b/src/pdumper.c
@@ -2860,13 +2860,18 @@ dump_subr (struct dump_context *ctx, const struct Lisp_Subr *subr)
struct Lisp_Subr out;
dump_object_start (ctx, &out, sizeof (out));
DUMP_FIELD_COPY (&out, subr, header.size);
- if (NATIVE_COMP_FLAG && !NILP (subr->native_comp_u[0]))
+#ifdef HAVE_NATIVE_COMP
+ bool native_comp = !NILP (subr->native_comp_u);
+#else
+ bool native_comp = false;
+#endif
+ if (native_comp)
out.function.a0 = NULL;
else
dump_field_emacs_ptr (ctx, &out, subr, &subr->function.a0);
DUMP_FIELD_COPY (&out, subr, min_args);
DUMP_FIELD_COPY (&out, subr, max_args);
- if (NATIVE_COMP_FLAG && !NILP (subr->native_comp_u[0]))
+ if (native_comp)
{
dump_field_fixup_later (ctx, &out, subr, &subr->symbol_name);
dump_remember_cold_op (ctx,
@@ -2880,19 +2885,16 @@ dump_subr (struct dump_context *ctx, const struct Lisp_Subr *subr)
dump_field_emacs_ptr (ctx, &out, subr, &subr->intspec);
}
DUMP_FIELD_COPY (&out, subr, doc);
- if (NATIVE_COMP_FLAG)
- {
- dump_field_lv (ctx, &out, subr, &subr->native_comp_u[0], WEIGHT_NORMAL);
- if (!NILP (subr->native_comp_u[0]))
- dump_field_fixup_later (ctx, &out, subr, &subr->native_c_name[0]);
+#ifdef HAVE_NATIVE_COMP
+ dump_field_lv (ctx, &out, subr, &subr->native_comp_u, WEIGHT_NORMAL);
+ if (!NILP (subr->native_comp_u))
+ dump_field_fixup_later (ctx, &out, subr, &subr->native_c_name);
- dump_field_lv (ctx, &out, subr, &subr->lambda_list[0], WEIGHT_NORMAL);
- dump_field_lv (ctx, &out, subr, &subr->type[0], WEIGHT_NORMAL);
- }
+ dump_field_lv (ctx, &out, subr, &subr->lambda_list, WEIGHT_NORMAL);
+ dump_field_lv (ctx, &out, subr, &subr->type, WEIGHT_NORMAL);
+#endif
dump_off subr_off = dump_object_finish (ctx, &out, sizeof (out));
- if (NATIVE_COMP_FLAG
- && ctx->flags.dump_object_contents
- && !NILP (subr->native_comp_u[0]))
+ if (native_comp && ctx->flags.dump_object_contents)
/* We'll do the final addr relocation during VERY_LATE_RELOCS time
after the compilation units has been loaded. */
dump_push (&ctx->dump_relocs[VERY_LATE_RELOCS],
@@ -3422,9 +3424,9 @@ dump_cold_native_subr (struct dump_context *ctx, Lisp_Object subr)
dump_remember_fixup_ptr_raw
(ctx,
- subr_offset + dump_offsetof (struct Lisp_Subr, native_c_name[0]),
+ subr_offset + dump_offsetof (struct Lisp_Subr, native_c_name),
ctx->offset);
- const char *c_name = XSUBR (subr)->native_c_name[0];
+ const char *c_name = XSUBR (subr)->native_c_name;
dump_write (ctx, c_name, 1 + strlen (c_name));
}
#endif
@@ -5361,20 +5363,16 @@ dump_do_dump_relocation (const uintptr_t dump_base,
}
case RELOC_NATIVE_SUBR:
{
- if (!NATIVE_COMP_FLAG)
- /* This cannot happen. */
- emacs_abort ();
-
/* When resurrecting from a dump given non all the original
native compiled subrs may be still around we can't rely on
a 'top_level_run' mechanism, we revive them one-by-one
here. */
struct Lisp_Subr *subr = dump_ptr (dump_base, reloc_offset);
struct Lisp_Native_Comp_Unit *comp_u =
- XNATIVE_COMP_UNIT (subr->native_comp_u[0]);
+ XNATIVE_COMP_UNIT (subr->native_comp_u);
if (!comp_u->handle)
error ("NULL handle in compilation unit %s", SSDATA (comp_u->file));
- const char *c_name = subr->native_c_name[0];
+ const char *c_name = subr->native_c_name;
eassert (c_name);
void *func = dynlib_sym (comp_u->handle, c_name);
if (!func)
diff --git a/test/lisp/tab-bar-tests.el b/test/lisp/tab-bar-tests.el
new file mode 100644
index 00000000000..7212ce89167
--- /dev/null
+++ b/test/lisp/tab-bar-tests.el
@@ -0,0 +1,51 @@
+;;; tab-bar-tests.el --- Tests for tab-bar.el -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2021 Free Software Foundation, Inc.
+
+;; Author: Juri Linkov <juri@linkov.net>
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Code:
+
+(require 'ert)
+
+(defun tab-bar-tests-close-other-tabs (arg)
+ (tab-bar-tabs-set nil)
+ (tab-rename "1")
+ (tab-new) (tab-rename "2") ;; (tab-switch "2")
+ (tab-new) (tab-rename "3") ;; (tab-switch "3")
+ (should (eq (length (tab-bar-tabs)) 3))
+ (should (equal (alist-get 'name (tab-bar--current-tab-find)) "3"))
+ (tab-bar-close-other-tabs arg)
+ (should (equal (alist-get 'name (tab-bar--current-tab-find))
+ (if arg (number-to-string (max 1 (min arg 3))) "3")))
+ (should (eq (length (tab-bar-tabs)) 1))
+ (should (eq (length tab-bar-closed-tabs) 2))
+ (tab-undo)
+ (tab-undo)
+ (should (equal (tab-undo) "No more closed tabs to undo"))
+ (should (eq (length (tab-bar-tabs)) 3))
+ (should (eq (length tab-bar-closed-tabs) 0)))
+
+(ert-deftest tab-bar-tests-close-other-tabs-default ()
+ (tab-bar-tests-close-other-tabs nil))
+
+(ert-deftest tab-bar-tests-close-other-tabs-with-arg ()
+ (dotimes (i 5) (tab-bar-tests-close-other-tabs i)))
+
+(provide 'tab-bar-tests)
+;;; tab-bar-tests.el ends here