emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

feature/android a336fd98a1 2/2: Merge remote-tracking branch 'origin/mas


From: Po Lu
Subject: feature/android a336fd98a1 2/2: Merge remote-tracking branch 'origin/master' into feature/android
Date: Sat, 14 Jan 2023 22:57:40 -0500 (EST)

branch: feature/android
commit a336fd98a1ed1f97d69652cade46f99868f7c7fb
Merge: 6e2bc91d92 16579f6ed7
Author: Po Lu <luangruo@yahoo.com>
Commit: Po Lu <luangruo@yahoo.com>

    Merge remote-tracking branch 'origin/master' into feature/android
---
 build-aux/update-copyright                         |   4 +-
 configure.ac                                       |   4 +-
 doc/lispref/parsing.texi                           |   8 +-
 doc/misc/eglot.texi                                |   2 +-
 doc/misc/eww.texi                                  |   7 +-
 etc/NEWS                                           |  18 ++
 etc/NEWS.29                                        |  32 ++-
 etc/PROBLEMS                                       |  12 +
 lib/gnulib.mk.in                                   |   2 +
 lib/qcopy-acl.c                                    |  36 ++-
 lib/verify.h                                       |   8 +-
 lisp/apropos.el                                    | 242 ++++++++++-----------
 lisp/doc-view.el                                   |   2 +-
 lisp/emacs-lisp/ert-x.el                           |   2 +-
 lisp/emacs-lisp/pp.el                              |  12 +-
 lisp/eshell/em-cmpl.el                             |   2 +-
 lisp/eshell/em-elecslash.el                        |   2 +-
 lisp/eshell/em-hist.el                             |   6 +-
 lisp/eshell/em-prompt.el                           | 117 +++++-----
 lisp/eshell/em-rebind.el                           |   6 +-
 lisp/eshell/esh-io.el                              |   6 +-
 lisp/eshell/esh-mode.el                            |  58 ++---
 lisp/eshell/esh-proc.el                            |  22 +-
 lisp/htmlfontify.el                                |  24 +-
 lisp/international/mule.el                         |   3 +-
 lisp/net/eww.el                                    |  11 +-
 lisp/proced.el                                     | 104 ++++++---
 lisp/progmodes/c-ts-mode.el                        |  11 +-
 lisp/progmodes/csharp-mode.el                      |   5 +
 lisp/progmodes/eglot.el                            |   3 +-
 lisp/progmodes/java-ts-mode.el                     |  18 +-
 lisp/simple.el                                     |   8 +
 lisp/subr.el                                       |   2 +-
 lwlib/Makefile.in                                  |   2 +-
 m4/acl.m4                                          |   4 +-
 m4/assert_h.m4                                     |   4 +-
 m4/gettime.m4                                      |  31 ++-
 m4/gnulib-common.m4                                |   2 +-
 m4/gnulib-comp.m4                                  |   9 +
 m4/utimens.m4                                      |   6 +-
 m4/xattr.m4                                        |  43 ++++
 msdos/sed1v2.inp                                   |   1 +
 src/Makefile.in                                    |   3 +-
 src/coding.c                                       |   2 +-
 src/fns.c                                          |   9 +
 src/pgtkterm.c                                     |   3 +-
 src/treesit.c                                      | 162 +++++++++-----
 src/treesit.h                                      |   1 +
 test/lisp/eshell/em-prompt-tests.el                | 118 ++++++++++
 test/lisp/eshell/eshell-tests.el                   |  15 +-
 test/lisp/minibuffer-tests.el                      |   2 +-
 test/lisp/proced-tests.el                          |  17 ++
 .../lisp/progmodes/c-ts-mode-resources/indent.erts |  44 ++++
 test/lisp/progmodes/c-ts-mode-tests.el             |  31 +++
 test/src/coding-tests.el                           |  30 +--
 55 files changed, 945 insertions(+), 393 deletions(-)

diff --git a/build-aux/update-copyright b/build-aux/update-copyright
index ce919bac72..99196fceef 100755
--- a/build-aux/update-copyright
+++ b/build-aux/update-copyright
@@ -137,7 +137,7 @@
 eval 'exec perl -wSx -0777 -pi "$0" "$@"'
      if 0;
 
-my $VERSION = '2020-04-04.15:07'; # UTC
+my $VERSION = '2023-01-11.04:24'; # UTC
 # The definition above must lie within the first 8 lines in order
 # for the Emacs time-stamp write hook (at end) to update it.
 # If you change this file with Emacs, please let the write hook
@@ -280,7 +280,7 @@ if (defined $stmt_re)
           }
 
         # Replace the old copyright statement.
-        s/$stmt_re/$stmt_wrapped/;
+        s/$stmt_re/$stmt_wrapped/g;
       }
   }
 else
diff --git a/configure.ac b/configure.ac
index 333a28cc14..92cf58fdf2 100644
--- a/configure.ac
+++ b/configure.ac
@@ -6936,7 +6936,9 @@ if test "${HAVE_GTK}" = "yes"; then
 fi
 
 if test $USE_ACL -ne 0; then
-  ACL_SUMMARY="yes $LIB_ACL"
+  ACL_SUMMARY="yes"
+  test "$LIB_ACL" && ACL_SUMMARY="$ACL_SUMMARY $LIB_ACL"
+  test "$LIB_XATTR" && ACL_SUMMARY="$ACL_SUMMARY $LIB_XATTR"
 else
   ACL_SUMMARY=no
 fi
diff --git a/doc/lispref/parsing.texi b/doc/lispref/parsing.texi
index b55af912f9..e4a2524982 100644
--- a/doc/lispref/parsing.texi
+++ b/doc/lispref/parsing.texi
@@ -929,9 +929,13 @@ Here are some predicates on tree-sitter nodes:
 Checks if @var{object} is a tree-sitter syntax node.
 @end defun
 
+@cindex compare tree-sitter syntax nodes
+@cindex tree-sitter nodes, comparing
 @defun treesit-node-eq node1 node2
-Checks if @var{node1} and @var{node2} are the same node in a syntax
-tree.
+Checks if @var{node1} and @var{node2} refer to the same node in a
+tree-sitter syntax tree.  This function uses the same equivalence
+metric as @code{equal}.  You can also compare nodes using @code{equal}
+(@pxref{Equality Predicates}).
 @end defun
 
 @heading Property information
diff --git a/doc/misc/eglot.texi b/doc/misc/eglot.texi
index 253bf169cc..56151b5482 100644
--- a/doc/misc/eglot.texi
+++ b/doc/misc/eglot.texi
@@ -1104,7 +1104,7 @@ troubleshoot Eglot problems.  It also provides guidelines 
for
 reporting Eglot bugs in a way that facilitates their resolution.
 
 When you encounter problems with Eglot, try first using the commands
-@kbd{M-x eglot-events-server} and @kbd{M-x eglot-stderr-buffer}.  They
+@kbd{M-x eglot-events-buffer} and @kbd{M-x eglot-stderr-buffer}.  They
 pop up special buffers that can be used to inspect the communications
 between the Eglot and language server.  In many cases, this will
 indicate the problems or at least provide a hint.
diff --git a/doc/misc/eww.texi b/doc/misc/eww.texi
index bc556ed88e..836eb38503 100644
--- a/doc/misc/eww.texi
+++ b/doc/misc/eww.texi
@@ -92,9 +92,10 @@ searched via @code{eww-search-prefix}.  The default search 
engine is
 either prefix the file name with @code{file://} or use the command
 @kbd{M-x eww-open-file}.
 
-  If you invoke @code{eww} with a prefix argument, as in @w{@kbd{C-u
-M-x eww}}, it will create a new EWW buffer instead of reusing the
-default one, which is normally called @file{*eww*}.
+  If you invoke @code{eww} or @code{eww-open-file} with a prefix
+argument, as in @w{@kbd{C-u M-x eww}}, they will create a new EWW
+buffer instead of reusing the default one, which is normally called
+@file{*eww*}.
 
 @findex eww-quit
 @findex eww-reload
diff --git a/etc/NEWS b/etc/NEWS
index 90a6c6a052..068f7a27db 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -127,6 +127,15 @@ of arguments into a command, such as when defining 
aliases.  For more
 information, see the "(eshell) Dollars Expansion" node in the Eshell
 manual.
 
+---
+*** Eshell now uses 'field' properties in its output.
+In particular, this means that pressing the <home> key moves the point
+to the beginning of your input, not the beginning of the whole line.
+If you want to go back to the old behavior, add something like this to
+your configuration:
+
+    (keymap-set eshell-mode-map "<home>" #'eshell-bol-ignoring-prompt)
+
 +++
 *** 'eshell-read-aliases-list' is now an interactive command.
 After manually editing 'eshell-aliases-file', you can use this command
@@ -147,6 +156,15 @@ point is not in a comment or a string.  It is by default 
bound to
 *** New connection method "toolbox".
 This allow accessing system containers provided by Toolbox.
 
+** EWW
+
++++
+*** 'eww-open-file' can now display the file in a new buffer.
+By default, the command reuses the '*eww*' buffer, but if called with
+the new argument non-nil, it will use a new buffer instead.
+Interactively, invoke 'eww-open-file' with a prefix argument to
+activate this behavior.
+
 
 * New Modes and Packages in Emacs 30.1
 
diff --git a/etc/NEWS.29 b/etc/NEWS.29
index 16d17821b7..ac338da71e 100644
--- a/etc/NEWS.29
+++ b/etc/NEWS.29
@@ -1636,6 +1636,20 @@ randomness as before, or to use a bag).
 *** New user option 'battery-update-functions'.
 This can be used to trigger actions based on the battery status.
 
+** DocView
+
+---
+*** doc-view can now generate SVG images when viewing PDF files.
+If Emacs is built with SVG support, doc-view can generate SVG files
+when using MuPDF as the converter for PDF files, which generally leads
+to sharper images (especially when zooming), and allows customization
+of background and foreground color of the page via the new user
+options 'doc-view-svg-background' and 'doc-view-svg-foreground'.  To
+activate this behavior, set 'doc-view-mupdf-use-svg' to non-nil if
+your Emacs has SVG support.  Note that, with some versions of MuPDF,
+SVG generation is known to sometimes produce SVG files that are buggy
+or can take a long time to render.
+
 ** Enriched Mode
 
 +++
@@ -4321,15 +4335,21 @@ whose matches are to be replaced.  If these variables 
are nil (which
 is the default), 'query-replace' and 'query-replace-regexp' take the
 default value from the previous FROM-TO pair.
 
----
-** New user option 'pp-use-max-width'.
-If non-nil, 'pp' will attempt to limit the line length when formatting
-long lists and vectors.
+** Lisp pretty-printer ('pp')
 
 ---
-** New function 'pp-emacs-lisp-code'.
+*** New function 'pp-emacs-lisp-code'.
 'pp' formats general Lisp sexps.  This function does much the same,
-but applies formatting rules appropriate for Emacs Lisp code.
+but applies formatting rules appropriate for Emacs Lisp code.  Note
+that this could currently be quite slow, and is thus appropriate only
+for relatively small code fragments.
+
+---
+*** New user option 'pp-use-max-width'.
+If non-nil, 'pp' and all 'pp-*' commands that format the results, will
+attempt to limit the line length when formatting long lists and
+vectors.  This uses 'pp-emacs-lisp-code', and thus could be slow for
+large lists.
 
 +++
 ** New function 'file-has-changed-p'.
diff --git a/etc/PROBLEMS b/etc/PROBLEMS
index d4354e5f7a..9ef231d4b1 100644
--- a/etc/PROBLEMS
+++ b/etc/PROBLEMS
@@ -628,6 +628,18 @@ To work around the problem, customize the option
 'window-adjust-process-window-size-function' to "Do not adjust process
 window sizes" (Lisp value 'ignore').
 
+*** Displaying PDF files in DocView produces an empty buffer.
+
+This can happen if your Emacs is configured to convert PDF to SVG for
+display, and the version of the MuPDF package you have installed has a
+a known bug, whereby it sometimes produces invalid SVG images.
+Version 1.21 of MuPDF is known to be affected.
+
+The solution is either to upgrade or downgrade to a version of MuPDF
+that doesn't have this bug, or to disable conversion of PDF files to
+SVG images by customizing the user option 'doc-view-mupdf-use-svg'.
+Emacs will then convert PDF to PNG images instead.
+
 *** In Inferior Python mode, input is echoed and native completion doesn't 
work.
 <https://debbugs.gnu.org/cgi/bugreport.cgi?bug=25753>
 
diff --git a/lib/gnulib.mk.in b/lib/gnulib.mk.in
index 2ebf187e86..2097850c81 100644
--- a/lib/gnulib.mk.in
+++ b/lib/gnulib.mk.in
@@ -949,6 +949,7 @@ LIB_PTHREAD = @LIB_PTHREAD@
 LIB_PTHREAD_SIGMASK = @LIB_PTHREAD_SIGMASK@
 LIB_TIMER_TIME = @LIB_TIMER_TIME@
 LIB_WSOCK32 = @LIB_WSOCK32@
+LIB_XATTR = @LIB_XATTR@
 LIMITS_H = @LIMITS_H@
 LN_S_FILEONLY = @LN_S_FILEONLY@
 LTLIBGMP = @LTLIBGMP@
@@ -1041,6 +1042,7 @@ PROFILING_CFLAGS = @PROFILING_CFLAGS@
 PTHREAD_H_DEFINES_STRUCT_TIMESPEC = @PTHREAD_H_DEFINES_STRUCT_TIMESPEC@
 PTHREAD_SIGMASK_LIB = @PTHREAD_SIGMASK_LIB@
 PTRDIFF_T_SUFFIX = @PTRDIFF_T_SUFFIX@
+QCOPY_ACL_LIB = @QCOPY_ACL_LIB@
 RALLOC_OBJ = @RALLOC_OBJ@
 RANLIB = @RANLIB@
 REPLACE_ACCESS = @REPLACE_ACCESS@
diff --git a/lib/qcopy-acl.c b/lib/qcopy-acl.c
index 883bcf7d58..0f4159b7fd 100644
--- a/lib/qcopy-acl.c
+++ b/lib/qcopy-acl.c
@@ -23,6 +23,20 @@
 
 #include "acl-internal.h"
 
+#if USE_XATTR
+
+# include <attr/libattr.h>
+
+/* Returns 1 if NAME is the name of an extended attribute that is related
+   to permissions, i.e. ACLs.  Returns 0 otherwise.  */
+
+static int
+is_attr_permissions (const char *name, struct error_context *ctx)
+{
+  return attr_copy_action (name, ctx) == ATTR_ACTION_PERMISSIONS;
+}
+
+#endif  /* USE_XATTR */
 
 /* Copy access control lists from one file to another. If SOURCE_DESC is
    a valid file descriptor, use file descriptor operations, else use
@@ -39,13 +53,33 @@ int
 qcopy_acl (const char *src_name, int source_desc, const char *dst_name,
            int dest_desc, mode_t mode)
 {
-  struct permission_context ctx;
   int ret;
 
+#ifdef USE_XATTR
+  /* in case no ACLs present and also to set higher mode bits
+     we chmod before setting ACLs as doing it after could overwrite them
+     (especially true for NFSv4, posix ACL has that ugly "mask" hack that
+     nobody understands) */
+  ret = chmod_or_fchmod (dst_name, dest_desc, mode);
+  /* Rather than fiddling with acls one by one, we just copy the whole ACL 
xattrs
+     (Posix or NFSv4). Of course, that won't address ACLs conversion
+     (i.e. posix <-> nfs4) but we can't do it anyway, so for now, we don't care
+     Functions attr_copy_* return 0 in case we copied something OR nothing
+     to copy */
+  if (ret == 0)
+    ret = source_desc <= 0 || dest_desc <= 0
+      ? attr_copy_file (src_name, dst_name, is_attr_permissions, NULL)
+      : attr_copy_fd (src_name, source_desc, dst_name, dest_desc,
+                      is_attr_permissions, NULL);
+#else
+  /* no XATTR, so we proceed the old dusty way */
+  struct permission_context ctx;
+
   ret = get_permissions (src_name, source_desc, mode, &ctx);
   if (ret != 0)
     return -2;
   ret = set_permissions (&ctx, dst_name, dest_desc);
   free_permission_context (&ctx);
+#endif
   return ret;
 }
diff --git a/lib/verify.h b/lib/verify.h
index 17d6e78c81..b63cb26432 100644
--- a/lib/verify.h
+++ b/lib/verify.h
@@ -258,7 +258,9 @@ template <int w>
 
 /* @assert.h omit start@  */
 
-#if 3 < __GNUC__ + (3 < __GNUC_MINOR__ + (4 <= __GNUC_PATCHLEVEL__))
+#if defined __clang_major__ && __clang_major__ < 5
+# define _GL_HAS_BUILTIN_TRAP 0
+#elif 3 < __GNUC__ + (3 < __GNUC_MINOR__ + (4 <= __GNUC_PATCHLEVEL__))
 # define _GL_HAS_BUILTIN_TRAP 1
 #elif defined __has_builtin
 # define _GL_HAS_BUILTIN_TRAP __has_builtin (__builtin_trap)
@@ -266,7 +268,9 @@ template <int w>
 # define _GL_HAS_BUILTIN_TRAP 0
 #endif
 
-#if 4 < __GNUC__ + (5 <= __GNUC_MINOR__)
+#if defined __clang_major__ && __clang_major__ < 5
+# define _GL_HAS_BUILTIN_UNREACHABLE 0
+#elif 4 < __GNUC__ + (5 <= __GNUC_MINOR__)
 # define _GL_HAS_BUILTIN_UNREACHABLE 1
 #elif defined __has_builtin
 # define _GL_HAS_BUILTIN_UNREACHABLE __has_builtin (__builtin_unreachable)
diff --git a/lisp/apropos.el b/lisp/apropos.el
index 9b9615221c..e95f45f180 100644
--- a/lisp/apropos.el
+++ b/lisp/apropos.el
@@ -54,6 +54,8 @@
 
 ;;; Code:
 
+(eval-when-compile (require 'cl-lib))
+
 (defgroup apropos nil
   "Apropos commands for users and programmers."
   :group 'help
@@ -193,9 +195,6 @@ property list, WIDGET-DOC is the widget docstring, FACE-DOC 
is
 the face docstring, and CUS-GROUP-DOC is the custom group
 docstring.  Each docstring is either nil or a string.")
 
-(defvar apropos-item ()
-  "Current item in or for `apropos-accumulator'.")
-
 (defvar apropos-synonyms '(
   ("find" "open" "edit")
   ("kill" "cut")
@@ -886,6 +885,38 @@ Optional arg BUFFER (default: current buffer) is the 
buffer to check."
              (if (consp pattern) "keywords " "")
              pattern))))
 
+(defun apropos--map-preloaded-atoms (f)
+  "Like `mapatoms' but only enumerates functions&vars that are predefined."
+  (let ((preloaded-regexp
+         (concat "\\`"
+                 (regexp-quote lisp-directory)
+                 (regexp-opt preloaded-file-list)
+                 "\\.elc?\\'")))
+    ;; FIXME: I find this regexp approach brittle.  Maybe a better
+    ;; option would be find/record the nthcdr of `load-history' which
+    ;; corresponds to the `load-history' state when we dumped.
+    ;; (Then again, maybe an even better approach would be to record the
+    ;; state of the `obarray' when we dumped, which we may also be able to
+    ;; use in `bytecomp' to provide a clean initial environment?)
+    (dolist (x load-history)
+      (when (string-match preloaded-regexp (car x))
+        (dolist (def (cdr x))
+          (cond
+           ((symbolp def) (funcall f def))
+           ((eq 'defun (car-safe def)) (funcall f (cdr def)))))))))
+
+(defun apropos--documentation-add (symbol doc pos)
+  (when (setq doc (apropos-documentation-internal doc))
+    (let ((score (apropos-score-doc doc))
+          (item (cdr (assq symbol apropos-accumulator))))
+      (unless item
+        (push (cons symbol
+                    (setq item (list (apropos-score-symbol symbol 2)
+                                     nil nil)))
+              apropos-accumulator))
+      (setf (nth pos item) doc)
+      (setcar item (+ (car item) score)))))
+
 ;;;###autoload
 (defun apropos-documentation (pattern &optional do-all)
   "Show symbols whose documentation contains matches for PATTERN.
@@ -894,10 +925,11 @@ or a regexp (using some regexp special characters).  If 
it is a word,
 search for matches for that word as a substring.  If it is a list of words,
 search for matches for any two (or more) of those words.
 
-Note that by default this command only searches in the file specified by
-`internal-doc-file-name'; i.e., the etc/DOC file.  With \\[universal-argument] 
prefix,
-or if `apropos-do-all' is non-nil, it searches all currently defined
-documentation strings.
+Note that by default this command only searches in the functions predefined
+at Emacs startup, i.e., the primitives implemented in C or preloaded in the
+Emacs dump image.
+With \\[universal-argument] prefix, or if `apropos-do-all' is non-nil, it 
searches
+all currently defined documentation strings.
 
 Returns list of symbols and documentation found."
   ;; The doc used to say that DO-ALL includes key-bindings info in the
@@ -907,40 +939,28 @@ Returns list of symbols and documentation found."
   (setq apropos--current (list #'apropos-documentation pattern do-all))
   (apropos-parse-pattern pattern t)
   (or do-all (setq do-all apropos-do-all))
-  (setq apropos-accumulator () apropos-files-scanned ())
-  (with-temp-buffer
-    (let ((standard-input (current-buffer))
-          (apropos-sort-by-scores apropos-documentation-sort-by-scores)
-          f v sf sv)
-      (apropos-documentation-check-doc-file)
-      (if do-all
-          (mapatoms
-           (lambda (symbol)
-             (setq f (apropos-safe-documentation symbol)
-                   v (get symbol 'variable-documentation))
-             (if (integerp v) (setq v nil))
-             (setq f (apropos-documentation-internal f)
-                   v (apropos-documentation-internal v))
-             (setq sf (apropos-score-doc f)
-                   sv (apropos-score-doc v))
-             (if (or f v)
-                 (if (setq apropos-item
-                           (cdr (assq symbol apropos-accumulator)))
-                     (progn
-                       (if f
-                           (progn
-                             (setcar (nthcdr 1 apropos-item) f)
-                             (setcar apropos-item (+ (car apropos-item) sf))))
-                       (if v
-                           (progn
-                             (setcar (nthcdr 2 apropos-item) v)
-                             (setcar apropos-item (+ (car apropos-item) sv)))))
-                   (setq apropos-accumulator
-                         (cons (list symbol
-                                     (+ (apropos-score-symbol symbol 2) sf sv)
-                                     f v)
-                               apropos-accumulator)))))))
-      (apropos-print nil "\n----------------\n" nil t))))
+  (let ((apropos-accumulator ())
+        (apropos-files-scanned ())
+        (delayed (make-hash-table :test #'equal)))
+    (with-temp-buffer
+      (let ((standard-input (current-buffer))
+            (apropos-sort-by-scores apropos-documentation-sort-by-scores)
+            f v)
+        (apropos-documentation-check-doc-file)
+        (funcall
+         (if do-all #'mapatoms #'apropos--map-preloaded-atoms)
+         (lambda (symbol)
+           (setq f (apropos-safe-documentation symbol)
+                 v (get symbol 'variable-documentation))
+           (if (integerp v) (setq v nil))
+           (if (consp f)
+               (push (list symbol (cdr f) 1) (gethash (car f) delayed))
+             (apropos--documentation-add symbol f 1))
+           (if (consp v)
+               (push (list symbol (cdr v) 2) (gethash (car v) delayed))
+             (apropos--documentation-add symbol v 2))))
+        (maphash #'apropos--documentation-add-from-elc delayed)
+        (apropos-print nil "\n----------------\n" nil t)))))
 
 
 (defun apropos-value-internal (predicate symbol function)
@@ -961,11 +981,11 @@ Returns list of symbols and documentation found."
       symbol)))
 
 (defun apropos-documentation-internal (doc)
+  ;; By the time we get here, refs to DOC or to .elc files should have
+  ;; been converted into actual strings.
+  (cl-assert (not (or (consp doc) (integerp doc))))
   (cond
-   ((consp doc)
-    (apropos-documentation-check-elc-file (car doc)))
-   ((and doc
-         ;; Sanity check in case bad data sneaked into the
+   ((and ;; Sanity check in case bad data sneaked into the
          ;; documentation slot.
          (stringp doc)
          (string-match apropos-all-words-regexp doc)
@@ -1032,87 +1052,51 @@ non-nil."
                        ;; So we exclude them.
                        (cond ((= 3 type) (boundp symbol))
                              ((= 2 type) (fboundp symbol))))
-             (or (and (setq apropos-item (assq symbol apropos-accumulator))
-                      (setcar (cdr apropos-item)
-                              (apropos-score-doc doc)))
-                 (setq apropos-item (list symbol
-                                          (+ (apropos-score-symbol symbol 2)
-                                             (apropos-score-doc doc))
-                                          nil nil)
-                       apropos-accumulator (cons apropos-item
-                                                 apropos-accumulator)))
-             (when apropos-match-face
-               (setq doc (substitute-command-keys doc))
-               (if (or (string-match apropos-pattern-quoted doc)
-                       (string-match apropos-all-words-regexp doc))
-                   (put-text-property (match-beginning 0)
-                                      (match-end 0)
-                                      'face apropos-match-face doc)))
-             (setcar (nthcdr type apropos-item) doc))))
+              (let ((apropos-item (assq symbol apropos-accumulator)))
+               (or (and apropos-item
+                        (setcar (cdr apropos-item)
+                                (apropos-score-doc doc)))
+                   (setq apropos-item (list symbol
+                                            (+ (apropos-score-symbol symbol 2)
+                                               (apropos-score-doc doc))
+                                            nil nil)
+                         apropos-accumulator (cons apropos-item
+                                                   apropos-accumulator)))
+               (when apropos-match-face
+                 (setq doc (substitute-command-keys doc))
+                 (if (or (string-match apropos-pattern-quoted doc)
+                         (string-match apropos-all-words-regexp doc))
+                     (put-text-property (match-beginning 0)
+                                        (match-end 0)
+                                        'face apropos-match-face doc)))
+               (setcar (nthcdr type apropos-item) doc)))))
       (setq sepa (goto-char sepb)))))
 
-(defun apropos-documentation-check-elc-file (file)
-  ;; .elc files have the location of the file specified as #$, but for
-  ;; built-in files, that's a relative name (while for the rest, it's
-  ;; absolute).  So expand the name in the former case.
-  (unless (file-name-absolute-p file)
-    (setq file (expand-file-name file lisp-directory)))
-  (if (or (member file apropos-files-scanned)
-          (not (file-exists-p file)))
-      nil
-    (let (symbol doc beg end this-is-a-variable)
-      (setq apropos-files-scanned (cons file apropos-files-scanned))
-      (erase-buffer)
-      (insert-file-contents file)
-      (while (search-forward "\n#@" nil t)
-       ;; Read the comment length, and advance over it.
-       (setq end (read)
-             beg (1+ (point))
-             end (+ (point) end -1))
-       (forward-char)
-       (if (save-restriction
+(defun apropos--documentation-add-from-elc (file defs)
+  (erase-buffer)
+  (insert-file-contents
+   (if (file-name-absolute-p file) file
+     (expand-file-name file lisp-directory)))
+  (pcase-dolist (`(,symbol ,begbyte ,pos) defs)
+    ;; We presume the file-bytes are the same as the buffer bytes,
+    ;; which should indeed be the case because .elc files use the
+    ;; `emacs-internal' encoding.
+    (let* ((beg (byte-to-position (+ (point-min) begbyte)))
+           (sizeend (1- beg))
+           (size (save-excursion
+                   (goto-char beg)
+                   (skip-chars-backward " 0-9")
+                   (cl-assert (looking-back "#@" (- (point) 2)))
+                   (string-to-number (buffer-substring (point) sizeend))))
+           (end (byte-to-position (+ begbyte size -1))))
+      (when (save-restriction
              ;; match ^ and $ relative to doc string
              (narrow-to-region beg end)
+             (goto-char (point-min))
              (re-search-forward apropos-all-words-regexp nil t))
-           (progn
-             (goto-char (+ end 2))
-             (setq doc (buffer-substring beg end)
-                   end (- (match-end 0) beg)
-                   beg (- (match-beginning 0) beg))
-             (when (apropos-true-hit-doc doc)
-               (setq this-is-a-variable (looking-at "(def\\(var\\|const\\) ")
-                     symbol (progn
-                              (skip-chars-forward "(a-z")
-                              (forward-char)
-                              (read))
-                     symbol (if (consp symbol)
-                                (nth 1 symbol)
-                              symbol))
-               (if (if this-is-a-variable
-                       (get symbol 'variable-documentation)
-                     (and (fboundp symbol) (apropos-safe-documentation 
symbol)))
-                   (progn
-                     (or (and (setq apropos-item (assq symbol 
apropos-accumulator))
-                              (setcar (cdr apropos-item)
-                                      (+ (cadr apropos-item) 
(apropos-score-doc doc))))
-                         (setq apropos-item (list symbol
-                                                  (+ (apropos-score-symbol 
symbol 2)
-                                                     (apropos-score-doc doc))
-                                                  nil nil)
-                               apropos-accumulator (cons apropos-item
-                                                         apropos-accumulator)))
-                     (when apropos-match-face
-                       (setq doc (substitute-command-keys doc))
-                       (if (or (string-match apropos-pattern-quoted doc)
-                               (string-match apropos-all-words-regexp doc))
-                           (put-text-property (match-beginning 0)
-                                              (match-end 0)
-                                              'face apropos-match-face doc)))
-                     (setcar (nthcdr (if this-is-a-variable 3 2)
-                                     apropos-item)
-                             doc))))))))))
-
-
+       (let ((doc (buffer-substring beg end)))
+         (when (apropos-true-hit-doc doc)
+           (apropos--documentation-add symbol doc pos)))))))
 
 (defun apropos-safe-documentation (function)
   "Like `documentation', except it avoids calling `get_doc_string'.
@@ -1229,14 +1213,16 @@ as a heading."
                   (put-text-property (- (point) 3) (point)
                                      'face 'apropos-keybinding)))
             (terpri))
-         (apropos-print-doc 2
+         (apropos-print-doc apropos-item
+                            2
                             (if (commandp symbol)
                                 'apropos-command
                               (if (macrop symbol)
                                   'apropos-macro
                                 'apropos-function))
                             (not nosubst))
-         (apropos-print-doc 3
+         (apropos-print-doc apropos-item
+                            3
                             (if (custom-variable-p symbol)
                                 'apropos-user-option
                               'apropos-variable)
@@ -1254,10 +1240,10 @@ as a heading."
                                   (lambda (_)
                                     (message "Value: %s" value))))
               (insert "\n")))
-         (apropos-print-doc 7 'apropos-group t)
-         (apropos-print-doc 6 'apropos-face t)
-         (apropos-print-doc 5 'apropos-widget t)
-         (apropos-print-doc 4 'apropos-plist nil))
+         (apropos-print-doc apropos-item 7 'apropos-group t)
+         (apropos-print-doc apropos-item 6 'apropos-face t)
+         (apropos-print-doc apropos-item 5 'apropos-widget t)
+         (apropos-print-doc apropos-item 4 'apropos-plist nil))
         (setq-local truncate-partial-width-windows t)
         (setq-local truncate-lines t)))
     (when help-window-select
@@ -1265,7 +1251,7 @@ as a heading."
   (prog1 apropos-accumulator
     (setq apropos-accumulator ())))    ; permit gc
 
-(defun apropos-print-doc (i type do-keys)
+(defun apropos-print-doc (apropos-item i type do-keys)
   (let ((doc (nth i apropos-item)))
     (when (stringp doc)
       (if apropos-compact-layout
diff --git a/lisp/doc-view.el b/lisp/doc-view.el
index 7c272f52fb..0303fec67a 100644
--- a/lisp/doc-view.el
+++ b/lisp/doc-view.el
@@ -212,7 +212,7 @@ are available (see Info node `(emacs)Document View')."
 (defcustom doc-view-mupdf-use-svg (image-type-available-p 'svg)
   "Whether to use svg images for PDF files."
   :type 'boolean
-  :version "29.1")
+  :version "30.1")
 
 (defcustom doc-view-imenu-enabled (and (executable-find "mutool") t)
   "Whether to generate an imenu outline when \"mutool\" is available."
diff --git a/lisp/emacs-lisp/ert-x.el b/lisp/emacs-lisp/ert-x.el
index 83705ca5b8..98a017c8a8 100644
--- a/lisp/emacs-lisp/ert-x.el
+++ b/lisp/emacs-lisp/ert-x.el
@@ -496,7 +496,7 @@ See also `ert-with-temp-directory'."
              (progn ,@body)
            (ignore-errors
              ,@(when buffer
-                 (list `(with-current-buffer buf
+                 (list `(with-current-buffer ,buffer
                           (set-buffer-modified-p nil))
                        `(kill-buffer ,buffer))))
            (ignore-errors
diff --git a/lisp/emacs-lisp/pp.el b/lisp/emacs-lisp/pp.el
index ebda37419f..e6e3cd6c6f 100644
--- a/lisp/emacs-lisp/pp.el
+++ b/lisp/emacs-lisp/pp.el
@@ -47,7 +47,9 @@ Otherwise this should be a number."
 
 (defcustom pp-use-max-width nil
   "If non-nil, `pp'-related functions will try to fold lines.
-The target width is given by the `pp-max-width' variable."
+The target width is given by the `pp-max-width' variable.
+Note that this could slow down `pp' considerably when formatting
+large lists."
   :type 'boolean
   :version "29.1")
 
@@ -162,14 +164,15 @@ Also add the value to the front of the list in the 
variable `values'."
   (message "Evaluating...")
   (let ((result (eval expression lexical-binding)))
     (values--store-value result)
-    (pp-display-expression result "*Pp Eval Output*")))
+    (pp-display-expression result "*Pp Eval Output*" pp-use-max-width)))
 
 ;;;###autoload
 (defun pp-macroexpand-expression (expression)
   "Macroexpand EXPRESSION and pretty-print its value."
   (interactive
    (list (read--expression "Macroexpand: ")))
-  (pp-display-expression (macroexpand-1 expression) "*Pp Macroexpand Output*"))
+  (pp-display-expression (macroexpand-1 expression) "*Pp Macroexpand Output*"
+                         pp-use-max-width))
 
 (defun pp-last-sexp ()
   "Read sexp before point.  Ignore leading comment characters."
@@ -219,7 +222,8 @@ Ignores leading comment characters."
 ;;;###autoload
 (defun pp-emacs-lisp-code (sexp)
   "Insert SEXP into the current buffer, formatted as Emacs Lisp code.
-Use the `pp-max-width' variable to control the desired line length."
+Use the `pp-max-width' variable to control the desired line length.
+Note that this could be slow for large SEXPs."
   (require 'edebug)
   (let ((obuf (current-buffer)))
     (with-temp-buffer
diff --git a/lisp/eshell/em-cmpl.el b/lisp/eshell/em-cmpl.el
index 94ec5e8f1d..4206ad048f 100644
--- a/lisp/eshell/em-cmpl.el
+++ b/lisp/eshell/em-cmpl.el
@@ -312,7 +312,7 @@ to writing a completion function."
             (eshell-interactive-process-p))
     (eshell--pcomplete-insert-tab))
   (let ((end (point-marker))
-       (begin (save-excursion (eshell-bol) (point)))
+       (begin (save-excursion (beginning-of-line) (point)))
        (posns (list t))
        args delim)
     (when (and pcomplete-allow-modifications
diff --git a/lisp/eshell/em-elecslash.el b/lisp/eshell/em-elecslash.el
index 80bc0f031e..2b003f58dc 100644
--- a/lisp/eshell/em-elecslash.el
+++ b/lisp/eshell/em-elecslash.el
@@ -72,7 +72,7 @@ insertion."
     (delete-char -1)
     (let ((tilde-before (eq ?~ (char-before)))
           (command (save-excursion
-                     (eshell-bol)
+                     (beginning-of-line)
                      (skip-syntax-forward " ")
                      (thing-at-point 'sexp)))
           (prefix (file-remote-p default-directory)))
diff --git a/lisp/eshell/em-hist.el b/lisp/eshell/em-hist.el
index 05e9598f53..6e0e471d91 100644
--- a/lisp/eshell/em-hist.el
+++ b/lisp/eshell/em-hist.el
@@ -555,7 +555,7 @@ See also `eshell-read-history'."
 (defun eshell-hist-parse-arguments (&optional b e)
   "Parse current command arguments in a history-code-friendly way."
   (let ((end (or e (point)))
-       (begin (or b (save-excursion (eshell-bol) (point))))
+       (begin (or b (save-excursion (beginning-of-line) (point))))
        (posb (list t))
        (pose (list t))
        (textargs (list t))
@@ -913,7 +913,7 @@ If N is negative, search forwards for the -Nth following 
match."
                                eshell-next-matching-input-from-input)))
       ;; Starting a new search
       (setq eshell-matching-input-from-input-string
-           (buffer-substring (save-excursion (eshell-bol) (point))
+           (buffer-substring (save-excursion (beginning-of-line) (point))
                              (point))
            eshell-history-index nil))
   (eshell-previous-matching-input
@@ -933,7 +933,7 @@ If N is negative, search backwards for the -Nth previous 
match."
   (if (get-text-property (point) 'history)
       (progn (beginning-of-line) t)
     (let ((before (point)))
-      (eshell-bol)
+      (beginning-of-line)
       (if (and (not (bolp))
               (<= (point) before))
          t
diff --git a/lisp/eshell/em-prompt.el b/lisp/eshell/em-prompt.el
index 575b5a595f..52d46282c5 100644
--- a/lisp/eshell/em-prompt.el
+++ b/lisp/eshell/em-prompt.el
@@ -29,6 +29,8 @@
 (require 'esh-mode)
 (eval-when-compile (require 'eshell))
 
+(require 'text-property-search)
+
 ;;;###autoload
 (progn
 (defgroup eshell-prompt nil
@@ -58,11 +60,12 @@ prompt."
   :group 'eshell-prompt)
 
 (defcustom eshell-prompt-regexp "^[^#$\n]* [#$] "
-  "A regexp which fully matches your eshell prompt.
-This setting is important, since it affects how eshell will interpret
-the lines that are passed to it.
-If this variable is changed, all Eshell buffers must be exited and
-re-entered for it to take effect."
+  "A regexp which fully matches your Eshell prompt.
+This is useful for navigating by paragraph using \
+\\[forward-paragraph] and \\[backward-paragraph].
+
+If this variable is changed, all Eshell buffers must be exited
+and re-entered for it to take effect."
   :type 'regexp
   :group 'eshell-prompt)
 
@@ -123,7 +126,6 @@ arriving, or after."
     (if eshell-prompt-regexp
         (setq-local paragraph-start eshell-prompt-regexp))
 
-    (setq-local eshell-skip-prompt-function #'eshell-skip-prompt)
     (eshell-prompt-mode)))
 
 (defun eshell-emit-prompt ()
@@ -134,72 +136,83 @@ arriving, or after."
   (if (not eshell-prompt-function)
       (set-marker eshell-last-output-end (point))
     (let ((prompt (funcall eshell-prompt-function)))
-      (and eshell-highlight-prompt
-          (add-text-properties 0 (length prompt)
-                               '(read-only t
-                                 font-lock-face eshell-prompt
-                                 front-sticky (font-lock-face read-only)
-                                 rear-nonsticky (font-lock-face read-only))
-                               prompt))
-      (eshell-interactive-print prompt)))
+      (add-text-properties
+       0 (length prompt)
+       (if eshell-highlight-prompt
+           '( read-only t
+              field prompt
+              font-lock-face eshell-prompt
+              front-sticky (read-only field font-lock-face)
+              rear-nonsticky (read-only field font-lock-face))
+         '( field prompt
+            front-sticky (field)
+            rear-nonsticky (field)))
+       prompt)
+      (eshell-interactive-filter nil prompt)))
   (run-hooks 'eshell-after-prompt-hook))
 
-(defun eshell-backward-matching-input (regexp arg)
-  "Search backward through buffer for match for REGEXP.
-Matches are searched for on lines that match `eshell-prompt-regexp'.
-With prefix argument N, search for Nth previous match.
-If N is negative, find the next or Nth next match."
-  (interactive (eshell-regexp-arg "Backward input matching (regexp): "))
-  (let* ((re (concat eshell-prompt-regexp ".*" regexp))
-        (pos (save-excursion (end-of-line (if (> arg 0) 0 1))
-                             (if (re-search-backward re nil t arg)
-                                 (point)))))
-    (if (null pos)
-       (progn (message "Not found")
-              (ding))
-      (goto-char pos)
-      (eshell-bol))))
-
 (defun eshell-forward-matching-input (regexp arg)
-  "Search forward through buffer for match for REGEXP.
-Matches are searched for on lines that match `eshell-prompt-regexp'.
-With prefix argument N, search for Nth following match.
-If N is negative, find the previous or Nth previous match."
+  "Search forward through buffer for command input that matches REGEXP.
+With prefix argument N, search for Nth next match.  If N is
+negative, find the Nth previous match."
   (interactive (eshell-regexp-arg "Forward input matching (regexp): "))
-  (eshell-backward-matching-input regexp (- arg)))
+  (let ((direction (if (> arg 0) 1 -1))
+        (count (abs arg)))
+    (unless (catch 'found
+              (while (> count 0)
+                (eshell-next-prompt direction)
+                (when (and (string-match regexp (field-string))
+                           (= (setq count (1- count)) 0))
+                  (throw 'found t))))
+      (message "Not found")
+      (ding))))
+
+(defun eshell-backward-matching-input (regexp arg)
+  "Search backward through buffer for command input that matches REGEXP.
+With prefix argument N, search for Nth previous match.  If N is
+negative, find the Nth next match."
+  (interactive (eshell-regexp-arg "Backward input matching (regexp): "))
+  (eshell-forward-matching-input regexp (- arg)))
 
 (defun eshell-next-prompt (n)
-  "Move to end of Nth next prompt in the buffer.
-See `eshell-prompt-regexp'."
+  "Move to end of Nth next prompt in the buffer."
   (interactive "p")
-  (if eshell-highlight-prompt
-      (progn
-        (while (< n 0)
-          (while (and (re-search-backward eshell-prompt-regexp nil t)
-                      (not (get-text-property (match-beginning 0) 
'read-only))))
-          (setq n (1+ n)))
-        (while (> n 0)
-          (while (and (re-search-forward eshell-prompt-regexp nil t)
-                      (not (get-text-property (match-beginning 0) 
'read-only))))
-          (setq n (1- n))))
-    (re-search-forward eshell-prompt-regexp nil t n))
-  (eshell-skip-prompt))
+  (if (natnump n)
+      (while (and (> n 0)
+                  (text-property-search-forward 'field 'prompt t))
+        (setq n (1- n)))
+    (let (match this-match)
+      (forward-line 0)           ; Don't count prompt on current line.
+      (while (and (< n 0)
+                  (setq this-match (text-property-search-backward
+                                    'field 'prompt t)))
+        (setq match this-match
+              n (1+ n)))
+      (when match
+        (goto-char (prop-match-end match))))))
 
 (defun eshell-previous-prompt (n)
-  "Move to end of Nth previous prompt in the buffer.
-See `eshell-prompt-regexp'."
+  "Move to end of Nth previous prompt in the buffer."
   (interactive "p")
-  (forward-line 0)            ; Don't count prompt on current line.
   (eshell-next-prompt (- n)))
 
 (defun eshell-skip-prompt ()
   "Skip past the text matching regexp `eshell-prompt-regexp'.
 If this takes us past the end of the current line, don't skip at all."
+  (declare (obsolete nil "30.1"))
   (let ((eol (line-end-position)))
     (if (and (looking-at eshell-prompt-regexp)
             (<= (match-end 0) eol))
        (goto-char (match-end 0)))))
 
+(defun eshell-bol-ignoring-prompt (arg)
+  "Move point to the beginning of the current line, past the prompt (if any).
+With argument ARG not nil or 1, move forward ARG - 1 lines
+first (see `move-beginning-of-line' for more information)."
+  (interactive "^p")
+  (let ((inhibit-field-text-motion t))
+    (move-beginning-of-line arg)))
+
 (provide 'em-prompt)
 
 ;; Local Variables:
diff --git a/lisp/eshell/em-rebind.el b/lisp/eshell/em-rebind.el
index 2c95d4fdff..f147d43230 100644
--- a/lisp/eshell/em-rebind.el
+++ b/lisp/eshell/em-rebind.el
@@ -50,9 +50,7 @@ the behavior of normal shells while the user editing new 
input text."
   :group 'eshell-rebind)
 
 (defcustom eshell-rebind-keys-alist
-  '(([(control ?a)] . eshell-bol)
-    ([home]         . eshell-bol)
-    ([(control ?d)] . eshell-delchar-or-maybe-eof)
+  '(([(control ?d)] . eshell-delchar-or-maybe-eof)
     ([backspace]    . eshell-delete-backward-char)
     ([delete]       . eshell-delete-backward-char)
     ([(control ?w)] . backward-kill-word)
@@ -190,7 +188,7 @@ lock it at that."
        (and eshell-remap-previous-input
             (setq begin
                   (save-excursion
-                    (eshell-bol)
+                    (beginning-of-line)
                     (and (not (bolp)) (point))))
             (>= pos begin)
             (<= pos (line-end-position))
diff --git a/lisp/eshell/esh-io.el b/lisp/eshell/esh-io.el
index 4dad4c7429..cccdb49ce2 100644
--- a/lisp/eshell/esh-io.el
+++ b/lisp/eshell/esh-io.el
@@ -74,6 +74,8 @@
 (eval-when-compile
   (require 'cl-lib))
 
+(declare-function eshell-interactive-print "esh-mode" (string))
+
 (defgroup eshell-io nil
   "Eshell's I/O management code provides a scheme for treating many
 different kinds of objects -- symbols, files, buffers, etc. -- as
@@ -597,8 +599,6 @@ after all printing is over with no argument."
   (eshell-print object)
   (eshell-print "\n"))
 
-(autoload 'eshell-output-filter "esh-mode")
-
 (defun eshell-output-object-to-target (object target)
   "Insert OBJECT into TARGET.
 Returns what was actually sent, or nil if nothing was sent."
@@ -608,7 +608,7 @@ Returns what was actually sent, or nil if nothing was sent."
 
    ((symbolp target)
     (if (eq target t)                   ; means "print to display"
-       (eshell-output-filter nil (eshell-stringify object))
+       (eshell-interactive-print (eshell-stringify object))
       (if (not (symbol-value target))
          (set target object)
        (setq object (eshell-stringify object))
diff --git a/lisp/eshell/esh-mode.el b/lisp/eshell/esh-mode.el
index d80f1d1f39..503d9ba1b6 100644
--- a/lisp/eshell/esh-mode.el
+++ b/lisp/eshell/esh-mode.el
@@ -155,7 +155,8 @@ number, if the function `eshell-truncate-buffer' is on
     eshell-watch-for-password-prompt)
   "Functions to call before output is displayed.
 These functions are only called for output that is displayed
-interactively, and not for output which is redirected."
+interactively (see `eshell-interactive-filter'), and not for
+output which is redirected."
   :type 'hook)
 
 (defcustom eshell-preoutput-filter-functions nil
@@ -175,6 +176,8 @@ This is used by `eshell-watch-for-password-prompt'."
   "A function called from beginning of line to skip the prompt."
   :type '(choice (const nil) function))
 
+(make-obsolete-variable 'eshell-skip-prompt-function nil "30.1")
+
 (defcustom eshell-status-in-mode-line t
   "If non-nil, let the user know a command is running in the mode line."
   :type 'boolean)
@@ -261,14 +264,13 @@ This is used by `eshell-watch-for-password-prompt'."
   "C-c"   'eshell-command-map
   "RET"   #'eshell-send-input
   "M-RET" #'eshell-queue-input
-  "C-M-l" #'eshell-show-output
-  "C-a"   #'eshell-bol)
+  "C-M-l" #'eshell-show-output)
 
 (defvar-keymap eshell-command-map
   :prefix 'eshell-command-map
   "M-o" #'eshell-mark-output
   "M-d" #'eshell-toggle-direct-send
-  "C-a" #'eshell-bol
+  "C-a" #'move-beginning-of-line
   "C-b" #'eshell-backward-argument
   "C-e" #'eshell-show-maximum-output
   "C-f" #'eshell-forward-argument
@@ -471,7 +473,7 @@ and the hook `eshell-exit-hook'."
 (defun eshell-move-argument (limit func property arg)
   "Move forward ARG arguments."
   (catch 'eshell-incomplete
-    (eshell-parse-arguments (save-excursion (eshell-bol) (point))
+    (eshell-parse-arguments (save-excursion (beginning-of-line) (point))
                            (line-end-position)))
   (let ((pos (save-excursion
               (funcall func 1)
@@ -504,12 +506,7 @@ and the hook `eshell-exit-hook'."
     (kill-ring-save begin (point))
     (yank)))
 
-(defun eshell-bol ()
-  "Go to the beginning of line, then skip past the prompt, if any."
-  (interactive)
-  (beginning-of-line)
-  (and eshell-skip-prompt-function
-       (funcall eshell-skip-prompt-function)))
+(define-obsolete-function-alias 'eshell-bol #'beginning-of-line "30.1")
 
 (defsubst eshell-push-command-mark ()
   "Push a mark at the end of the last input text."
@@ -525,9 +522,13 @@ Putting this function on `eshell-pre-command-hook' will 
mimic Plan 9's
 
 (custom-add-option 'eshell-pre-command-hook #'eshell-goto-input-start)
 
-(defsubst eshell-interactive-print (string)
+(defun eshell-interactive-print (string)
   "Print STRING to the eshell display buffer."
-  (eshell-output-filter nil string))
+  (when string
+    (add-text-properties 0 (length string)
+                         '(field command-output rear-nonsticky (field))
+                         string)
+    (eshell-interactive-filter nil string)))
 
 (defsubst eshell-begin-on-new-line ()
   "This function outputs a newline if not at beginning of line."
@@ -687,14 +688,14 @@ newline."
 
 (custom-add-option 'eshell-input-filter-functions 'eshell-kill-new)
 
-(defun eshell-output-filter (process string)
-  "Send the output from PROCESS (STRING) to the interactive display.
+(defun eshell-interactive-filter (buffer string)
+  "Send output (STRING) to the interactive display, using BUFFER.
 This is done after all necessary filtering has been done."
-  (let ((oprocbuf (if process (process-buffer process)
-                    (current-buffer)))
-        (inhibit-modification-hooks t))
-    (when (and string oprocbuf (buffer-name oprocbuf))
-      (with-current-buffer oprocbuf
+  (unless buffer
+    (setq buffer (current-buffer)))
+  (when (and string (buffer-live-p buffer))
+    (let ((inhibit-modification-hooks t))
+      (with-current-buffer buffer
         (let ((functions eshell-preoutput-filter-functions))
           (while (and functions string)
             (setq string (funcall (car functions) string))
@@ -851,7 +852,7 @@ With a prefix argument, narrows region to last command 
output."
   (if (> (point) eshell-last-output-end)
       (kill-region eshell-last-output-end (point))
     (let ((here (point)))
-      (eshell-bol)
+      (beginning-of-line)
       (kill-region (point) here))))
 
 (defun eshell-show-maximum-output (&optional interactive)
@@ -879,17 +880,18 @@ If SCROLLBACK is non-nil, clear the scrollback contents."
     (erase-buffer)))
 
 (defun eshell-get-old-input (&optional use-current-region)
-  "Return the command input on the current line."
+  "Return the command input on the current line.
+If USE-CURRENT-REGION is non-nil, return the current region."
   (if use-current-region
       (buffer-substring (min (point) (mark))
                        (max (point) (mark)))
     (save-excursion
-      (beginning-of-line)
-      (and eshell-skip-prompt-function
-          (funcall eshell-skip-prompt-function))
-      (let ((beg (point)))
-       (end-of-line)
-       (buffer-substring beg (point))))))
+      (let ((inhibit-field-text-motion t))
+        (end-of-line))
+      (let ((inhibit-field-text-motion)
+            (end (point)))
+        (beginning-of-line)
+        (buffer-substring (point) end)))))
 
 (defun eshell-copy-old-input ()
   "Insert after prompt old input at point as new input to be edited."
diff --git a/lisp/eshell/esh-proc.el b/lisp/eshell/esh-proc.el
index 8a803c67e4..9bae812c92 100644
--- a/lisp/eshell/esh-proc.el
+++ b/lisp/eshell/esh-proc.el
@@ -304,7 +304,7 @@ Used only on systems which do not support async 
subprocesses.")
                :name (concat (file-name-nondirectory command) "-stderr")
                :buffer (current-buffer)
                :filter (if (eshell-interactive-output-p eshell-error-handle)
-                           #'eshell-output-filter
+                           #'eshell-interactive-process-filter
                          #'eshell-insertion-filter)
                :sentinel #'eshell-sentinel))
         (eshell-record-process-properties stderr-proc eshell-error-handle))
@@ -320,7 +320,7 @@ Used only on systems which do not support async 
subprocesses.")
                :buffer (current-buffer)
                :command (cons command args)
                :filter (if (eshell-interactive-output-p)
-                           #'eshell-output-filter
+                           #'eshell-interactive-process-filter
                          #'eshell-insertion-filter)
                :sentinel #'eshell-sentinel
                :connection-type conn-type
@@ -381,7 +381,7 @@ Used only on systems which do not support async 
subprocesses.")
                  line (buffer-substring-no-properties lbeg lend))
            (set-buffer oldbuf)
            (if interact-p
-               (eshell-output-filter nil line)
+               (eshell-interactive-process-filter nil line)
              (eshell-output-object line))
            (setq lbeg lend)
            (set-buffer proc-buf))
@@ -402,6 +402,22 @@ Used only on systems which do not support async 
subprocesses.")
        (setq proc t))))
     proc))
 
+(defun eshell-interactive-process-filter (process string)
+  "Send the output from PROCESS (STRING) to the interactive display.
+This is done after all necessary filtering has been done."
+  (when string
+    (add-text-properties 0 (length string)
+                         '(field command-output rear-nonsticky (field))
+                         string)
+    (require 'esh-mode)
+    (declare-function eshell-interactive-filter "esh-mode" (buffer string))
+    (eshell-interactive-filter (if process (process-buffer process)
+                                 (current-buffer))
+                               string)))
+
+(define-obsolete-function-alias 'eshell-output-filter
+  #'eshell-interactive-process-filter "30.1")
+
 (defun eshell-insertion-filter (proc string)
   "Insert a string into the eshell buffer, or a process/file/buffer.
 PROC is the process for which we're inserting output.  STRING is the
diff --git a/lisp/htmlfontify.el b/lisp/htmlfontify.el
index c989a12d20..0959405081 100644
--- a/lisp/htmlfontify.el
+++ b/lisp/htmlfontify.el
@@ -78,7 +78,7 @@
 
 ;;; Code:
 
-(eval-when-compile (require 'cl-lib))
+(require 'cl-lib)
 (require 'cus-edit)
 
 (defconst hfy-meta-tags
@@ -372,11 +372,15 @@ otherwise."
   :tag   "istext-command"
   :type  '(string))
 
-(defcustom hfy-find-cmd
-  "find . -type f \\! -name \\*~ \\! -name \\*.flc \\! -path \\*/CVS/\\*"
-  "Find command used to harvest a list of files to attempt to fontify."
-  :tag   "find-command"
-  :type  '(string))
+(defcustom hfy-exclude-file-rules
+  '("\\.flc$"
+    "/CVS/.*"
+    ".*~$"
+    "/\\.git\\(?:/.*\\)?$")
+  "Define some regular expressions to exclude files"
+  :tag "exclude-rules"
+  :type '(list string)
+  :version "29.1")
 
 (defcustom hfy-display-class nil
   "Display class to use to determine which display class to use when
@@ -1826,8 +1830,12 @@ Strips any leading \"./\" from each filename."
   ;;(message "hfy-list-files");;DBUG
   ;; FIXME: this changes the dir of the current buffer.  Is that right??
   (cd directory)
-  (mapcar (lambda (F) (if (string-match "^./\\(.*\\)" F) (match-string 1 F) F))
-          (split-string (shell-command-to-string hfy-find-cmd))) )
+  (cl-remove-if (lambda (f)
+                  (or (null (file-regular-p f))
+                      (seq-some (lambda (r)
+                                  (string-match r f))
+                                hfy-exclude-file-rules)))
+                (directory-files-recursively "." ".*" nil t)))
 
 ;; strip the filename off, return a directory name
 ;; not a particularly thorough implementation, but it will be
diff --git a/lisp/international/mule.el b/lisp/international/mule.el
index 4f6addea38..eddd7b6407 100644
--- a/lisp/international/mule.el
+++ b/lisp/international/mule.el
@@ -863,7 +863,8 @@ This attribute is meaningful only when `:coding-type' is 
`utf-16' or
 VALUE must be `big' or `little' specifying big-endian and
 little-endian respectively.  The default value is `big'.
 
-This attribute is meaningful only when `:coding-type' is `utf-16'.
+Changing this attribute is only meaningful when `:coding-type'
+is `utf-16'.
 
 `:ccl-decoder' (required if :coding-type is `ccl')
 
diff --git a/lisp/net/eww.el b/lisp/net/eww.el
index 6e1e53ddaa..02f331697c 100644
--- a/lisp/net/eww.el
+++ b/lisp/net/eww.el
@@ -488,14 +488,17 @@ For more information, see Info node `(eww) Top'."
 ;;;###autoload (defalias 'browse-web 'eww)
 
 ;;;###autoload
-(defun eww-open-file (file)
-  "Render FILE using EWW."
-  (interactive "fFile: ")
+(defun eww-open-file (file &optional new-buffer)
+  "Render FILE using EWW.
+If NEW-BUFFER is non-nil (interactively, the prefix arg), use a
+new buffer instead of reusing the default EWW buffer."
+  (interactive "fFile: \nP")
   (let ((url-allow-non-local-files t))
     (eww (concat "file://"
                 (and (memq system-type '(windows-nt ms-dos))
                      "/")
-                (expand-file-name file)))))
+                (expand-file-name file))
+         new-buffer)))
 
 (defun eww--file-buffer (file)
   (with-current-buffer (generate-new-buffer " *eww file*")
diff --git a/lisp/proced.el b/lisp/proced.el
index 839b36b528..03a7f1bebd 100644
--- a/lisp/proced.el
+++ b/lisp/proced.el
@@ -792,6 +792,52 @@ Return nil if point is not on a process line."
     (if (looking-at "^. .")
         (get-text-property (match-end 0) 'proced-pid))))
 
+(defun proced--position-info (pos)
+  "Return information of the process at POS.
+
+The returned information will have the form `(PID KEY COLUMN)' where
+PID is the process ID of the process at point, KEY is the value of the
+proced-key text property at point, and COLUMN is the column for which the
+current value of the proced-key text property starts, or 0 if KEY is nil."
+  ;; If point is on a field, we try to return point to that field.
+  ;; Otherwise we try to return to the same column
+  (save-excursion
+    (goto-char pos)
+    (let ((pid (proced-pid-at-point))
+          (key (get-text-property (point) 'proced-key)))
+      (list pid key ; can both be nil
+            (if key
+                (if (get-text-property (1- (point)) 'proced-key)
+                    (- (point) (previous-single-property-change
+                                (point) 'proced-key))
+                  0)
+              (current-column))))))
+
+(defun proced--determine-pos (key column)
+  "Return position of point in the current line using KEY and COLUMN.
+
+Attempt to find the first position on the current line where the
+text property proced-key is equal to KEY.  If this is not possible, return
+the position of point of column COLUMN on the current line."
+  (save-excursion
+    (let (new-pos)
+      (if key
+          (let ((limit (line-end-position)) pos)
+            (while (and (not new-pos)
+                        (setq pos (next-property-change (point) nil limit)))
+              (goto-char pos)
+              (when (eq key (get-text-property (point) 'proced-key))
+                (forward-char (min column (- (next-property-change (point))
+                                             (point))))
+                (setq new-pos (point))))
+            (unless new-pos
+              ;; we found the process, but the field of point
+              ;; is not listed anymore
+              (setq new-pos (proced-move-to-goal-column))))
+        (setq new-pos (min (+ (line-beginning-position) column)
+                           (line-end-position))))
+      new-pos)))
+
 ;; proced mode
 
 (define-derived-mode proced-mode special-mode "Proced"
@@ -847,6 +893,7 @@ normal hook `proced-post-display-hook'.
   (setq-local revert-buffer-function #'proced-revert)
   (setq-local font-lock-defaults
               '(proced-font-lock-keywords t nil nil beginning-of-line))
+  (setq-local switch-to-buffer-preserve-window-point nil)
   (if (and (not proced-auto-update-timer) proced-auto-update-interval)
       (setq proced-auto-update-timer
             (run-at-time t proced-auto-update-interval
@@ -1889,17 +1936,10 @@ After updating a displayed Proced buffer run the normal 
hook
   (if (consp buffer-undo-list)
       (setq buffer-undo-list nil))
   (let ((buffer-undo-list t)
-        ;; If point is on a field, we try to return point to that field.
-        ;; Otherwise we try to return to the same column
-        (old-pos (let ((pid (proced-pid-at-point))
-                       (key (get-text-property (point) 'proced-key)))
-                   (list pid key ; can both be nil
-                         (if key
-                             (if (get-text-property (1- (point)) 'proced-key)
-                                 (- (point) (previous-single-property-change
-                                             (point) 'proced-key))
-                               0)
-                           (current-column)))))
+        (window-pos-infos
+         (mapcar (lambda (w) `(,w . ,(proced--position-info (window-point w))))
+                 (get-buffer-window-list (current-buffer) nil t)))
+        (old-pos (proced--position-info (point)))
         buffer-read-only mp-list)
     ;; remember marked processes (whatever the mark was)
     (goto-char (point-min))
@@ -1932,7 +1972,8 @@ After updating a displayed Proced buffer run the normal 
hook
     ;; Sometimes this puts point in the middle of the proced buffer
     ;; where it is not interesting.  Is there a better / more flexible 
solution?
     (goto-char (point-min))
-    (let (pid mark new-pos)
+
+    (let (pid mark new-pos win-points)
       (if (or mp-list (car old-pos))
           (while (not (eobp))
             (setq pid (proced-pid-at-point))
@@ -1941,28 +1982,25 @@ After updating a displayed Proced buffer run the normal 
hook
               (delete-char 1)
               (beginning-of-line))
             (when (eq (car old-pos) pid)
-              (if (nth 1 old-pos)
-                  (let ((limit (line-end-position)) pos)
-                    (while (and (not new-pos)
-                                (setq pos (next-property-change (point) nil 
limit)))
-                      (goto-char pos)
-                      (when (eq (nth 1 old-pos)
-                                (get-text-property (point) 'proced-key))
-                        (forward-char (min (nth 2 old-pos)
-                                           (- (next-property-change (point))
-                                              (point))))
-                        (setq new-pos (point))))
-                    (unless new-pos
-                      ;; we found the process, but the field of point
-                      ;; is not listed anymore
-                      (setq new-pos (proced-move-to-goal-column))))
-                (setq new-pos (min (+ (line-beginning-position) (nth 2 
old-pos))
-                                   (line-end-position)))))
+              (setq new-pos (proced--determine-pos (nth 1 old-pos)
+                                                   (nth 2 old-pos))))
+            (mapc (lambda (w-pos)
+                    (when (eq (cadr w-pos) pid)
+                      (push `(,(car w-pos) . ,(proced--determine-pos
+                                               (nth 1 (cdr w-pos))
+                                               (nth 2 (cdr w-pos))))
+                            win-points)))
+                  window-pos-infos)
             (forward-line)))
-      (if new-pos
-          (goto-char new-pos)
-        (goto-char (point-min))
-        (proced-move-to-goal-column)))
+      (let ((fallback (save-excursion (goto-char (point-min))
+                                      (proced-move-to-goal-column)
+                                      (point))))
+        (goto-char (or new-pos fallback))
+        ;; Update window points
+        (mapc (lambda (w-pos)
+                (set-window-point (car w-pos)
+                                  (alist-get (car w-pos) win-points fallback)))
+              window-pos-infos)))
     ;; update mode line
     ;; Does the long `mode-name' clutter the mode line?  It would be nice
     ;; to have some other location for displaying the values of the various
diff --git a/lisp/progmodes/c-ts-mode.el b/lisp/progmodes/c-ts-mode.el
index e929fe1dd8..b2151775e9 100644
--- a/lisp/progmodes/c-ts-mode.el
+++ b/lisp/progmodes/c-ts-mode.el
@@ -122,11 +122,13 @@ MODE is either `c' or `cpp'."
            ((node-is "else") parent-bol 0)
            ((node-is "case") parent-bol 0)
            ((node-is "preproc_arg") no-indent)
+           ;; `c-ts-mode--looking-at-star' has to come before
+           ;; `c-ts-mode--comment-2nd-line-matcher'.
+           ((and (parent-is "comment") c-ts-mode--looking-at-star)
+            c-ts-mode--comment-start-after-first-star -1)
            (c-ts-mode--comment-2nd-line-matcher
             c-ts-mode--comment-2nd-line-anchor
             1)
-           ((and (parent-is "comment") c-ts-mode--looking-at-star)
-            c-ts-mode--comment-start-after-first-star -1)
            ((parent-is "comment") prev-adaptive-prefix 0)
            (c-ts-mode--top-level-label-matcher point-min 1)
            ((node-is "labeled_statement") parent-bol 0)
@@ -724,7 +726,10 @@ ARG is passed to `fill-paragraph'."
           ;; Let `fill-paragraph' do its thing.
           (goto-char orig-point)
           (narrow-to-region start end)
-          (funcall #'fill-paragraph arg)
+          ;; We don't want to fill the region between START and
+          ;; START-MARKER, otherwise the filling function might delete
+          ;; some spaces there.
+          (fill-region start-marker end arg)
           ;; Unmask.
           (when start-marker
             (goto-char start-marker)
diff --git a/lisp/progmodes/csharp-mode.el b/lisp/progmodes/csharp-mode.el
index 32ec772169..870e6c84b4 100644
--- a/lisp/progmodes/csharp-mode.el
+++ b/lisp/progmodes/csharp-mode.el
@@ -640,6 +640,11 @@ compilation and evaluation time conflicts."
      ((parent-is "namespace_declaration") parent-bol 0)
      ((parent-is "class_declaration") parent-bol 0)
      ((parent-is "constructor_declaration") parent-bol 0)
+     ((parent-is "initializer_expression") parent-bol 
csharp-ts-mode-indent-offset)
+     ((match "{" "anonymous_object_creation_expression") parent-bol 0)
+     ((parent-is "anonymous_object_creation_expression") parent-bol 
csharp-ts-mode-indent-offset)
+     ((match "{" "object_creation_expression") parent-bol 0)
+     ((parent-is "object_creation_expression") parent-bol 0)
      ((parent-is "method_declaration") parent-bol 0)
      ((parent-is "enum_declaration") parent-bol 0)
      ((parent-is "operator_declaration") parent-bol 0)
diff --git a/lisp/progmodes/eglot.el b/lisp/progmodes/eglot.el
index c7fc443c8d..a846baa1b1 100644
--- a/lisp/progmodes/eglot.el
+++ b/lisp/progmodes/eglot.el
@@ -991,6 +991,7 @@ Return (MANAGED-MODE PROJECT CLASS CONTACT LANG-ID).  If 
INTERACTIVE is
 non-nil, maybe prompt user, else error as soon as something can't
 be guessed."
   (let* ((guessed-mode (if buffer-file-name major-mode))
+         (guessed-mode-name (and guessed-mode (symbol-name guessed-mode)))
          (main-mode
           (cond
            ((and interactive
@@ -1000,7 +1001,7 @@ be guessed."
              (completing-read
               "[eglot] Start a server to manage buffers of what major mode? "
               (mapcar #'symbol-name (eglot--all-major-modes)) nil t
-              (symbol-name guessed-mode) nil (symbol-name guessed-mode) nil)))
+              guessed-mode-name nil guessed-mode-name nil)))
            ((not guessed-mode)
             (eglot--error "Can't guess mode to manage for `%s'" 
(current-buffer)))
            (t guessed-mode)))
diff --git a/lisp/progmodes/java-ts-mode.el b/lisp/progmodes/java-ts-mode.el
index 8d432f1774..eac052ca4f 100644
--- a/lisp/progmodes/java-ts-mode.el
+++ b/lisp/progmodes/java-ts-mode.el
@@ -78,6 +78,7 @@
      ((parent-is "comment") prev-adaptive-prefix 0)
      ((parent-is "text_block") no-indent)
      ((parent-is "class_body") parent-bol java-ts-mode-indent-offset)
+     ((parent-is "annotation_type_body") parent-bol java-ts-mode-indent-offset)
      ((parent-is "interface_body") parent-bol java-ts-mode-indent-offset)
      ((parent-is "constructor_body") parent-bol java-ts-mode-indent-offset)
      ((parent-is "enum_body") parent-bol java-ts-mode-indent-offset)
@@ -85,6 +86,10 @@
      ((parent-is "record_declaration_body") parent-bol 
java-ts-mode-indent-offset)
      ((query "(method_declaration (block _ @indent))") parent-bol 
java-ts-mode-indent-offset)
      ((query "(method_declaration (block (_) @indent))") parent-bol 
java-ts-mode-indent-offset)
+     ((parent-is "local_variable_declaration") parent-bol 
java-ts-mode-indent-offset)
+     ((parent-is "expression_statement") parent-bol java-ts-mode-indent-offset)
+     ((parent-is "field_declaration") parent-bol java-ts-mode-indent-offset)
+     ((parent-is "return_statement") parent-bol java-ts-mode-indent-offset)
      ((parent-is "variable_declarator") parent-bol java-ts-mode-indent-offset)
      ((parent-is "method_invocation") parent-bol java-ts-mode-indent-offset)
      ((parent-is "switch_rule") parent-bol java-ts-mode-indent-offset)
@@ -221,7 +226,10 @@
    :language 'java
    :override t
    :feature 'definition
-   `((method_declaration
+   `((annotation_type_element_declaration
+      name: (identifier) @font-lock-function-name-face)
+
+     (method_declaration
       name: (identifier) @font-lock-function-name-face)
 
      (variable_declarator
@@ -311,6 +319,14 @@ Return nil if there is no name or if NODE is not a defun 
node."
                             "module_declaration")))
   (setq-local treesit-defun-name-function #'java-ts-mode--defun-name)
 
+  (setq-local treesit-sentence-type-regexp
+              (regexp-opt '("statement"
+                            "local_variable_declaration"
+                            "field_declaration"
+                            "module_declaration"
+                            "package_declaration"
+                            "import_declaration")))
+
   ;; Font-lock.
   (setq-local treesit-font-lock-settings java-ts-mode--font-lock-settings)
   (setq-local treesit-font-lock-feature-list
diff --git a/lisp/simple.el b/lisp/simple.el
index eedc5d7244..bbcb32cb04 100644
--- a/lisp/simple.el
+++ b/lisp/simple.el
@@ -9774,6 +9774,14 @@ Also see the `completion-auto-wrap' variable."
   (let ((tabcommand (member (this-command-keys) '("\t" [backtab])))
         pos)
     (catch 'bound
+      (when (and (bobp)
+                 (> n 0)
+                 (get-text-property (point) 'mouse-face)
+                 (not (get-text-property (point) 'first-completion)))
+        (let ((inhibit-read-only t))
+          (add-text-properties (point) (1+ (point)) '(first-completion t)))
+        (setq n (1- n)))
+
       (while (> n 0)
         (setq pos (point))
         ;; If in a completion, move to the end of it.
diff --git a/lisp/subr.el b/lisp/subr.el
index 9e50b1e7f9..1762c94a43 100644
--- a/lisp/subr.el
+++ b/lisp/subr.el
@@ -2567,7 +2567,7 @@ The variable list SPEC is the same as in `if-let'."
   (let ((done (gensym "done")))
     `(catch ',done
        (while t
-         (if-let* ,spec
+         (if-let ,spec
              (progn
                ,@body)
            (throw ',done nil))))))
diff --git a/lwlib/Makefile.in b/lwlib/Makefile.in
index 903461a2f4..70f6cd17d7 100644
--- a/lwlib/Makefile.in
+++ b/lwlib/Makefile.in
@@ -63,7 +63,7 @@ AUTO_DEPEND = @AUTO_DEPEND@
 DEPDIR = deps
 ifeq ($(AUTO_DEPEND),yes)
   DEPFLAGS = -MMD -MF $(DEPDIR)/$*.d -MP
-  -include $(ALLOBJS:%.o=$(DEPDIR)/%.d)
+  -include $(OBJS:%.o=$(DEPDIR)/%.d)
 else
   DEPFLAGS =
   include $(srcdir)/deps.mk
diff --git a/m4/acl.m4 b/m4/acl.m4
index e612f1ae34..dc9853a156 100644
--- a/m4/acl.m4
+++ b/m4/acl.m4
@@ -1,5 +1,5 @@
 # acl.m4 - check for access control list (ACL) primitives
-# serial 26
+# serial 27
 
 # Copyright (C) 2002, 2004-2023 Free Software Foundation, Inc.
 # This file is free software; the Free Software Foundation
@@ -17,7 +17,7 @@ AC_DEFUN([gl_FUNC_ACL_ARG],
 ])
 
 
-AC_DEFUN([gl_FUNC_ACL],
+AC_DEFUN_ONCE([gl_FUNC_ACL],
 [
   AC_REQUIRE([gl_FUNC_ACL_ARG])
   AC_CHECK_FUNCS_ONCE([fchmod])
diff --git a/m4/assert_h.m4 b/m4/assert_h.m4
index 6275f633a6..3801452ef0 100644
--- a/m4/assert_h.m4
+++ b/m4/assert_h.m4
@@ -18,7 +18,7 @@ AC_DEFUN([gl_ASSERT_H],
        [AC_LANG_PROGRAM(
           [[#if defined __clang__ && __STDC_VERSION__ < 202311
              #pragma clang diagnostic error "-Wc2x-extensions"
-             #pragma clang diagnostic error "-Wc++17-extensions"
+             #pragma clang diagnostic error "-Wc++1z-extensions"
             #endif
             #ifdef INCLUDE_ASSERT_H
              #include <assert.h>
@@ -60,7 +60,7 @@ AC_DEFUN([gl_ASSERT_H],
  /* Solaris 11.4 <assert.h> defines static_assert as a macro with 2 arguments.
     We need it also to be invocable with a single argument.  */
  #if defined __sun && (__STDC_VERSION__ - 0 >= 201112L) && !defined __cplusplus
-  #undef static_assert
+  #undef/**/static_assert
   #define static_assert _Static_assert
  #endif
 #endif])
diff --git a/m4/gettime.m4 b/m4/gettime.m4
index 06f32fe26c..7e353fcd00 100644
--- a/m4/gettime.m4
+++ b/m4/gettime.m4
@@ -1,4 +1,4 @@
-# gettime.m4 serial 12
+# gettime.m4 serial 13
 dnl Copyright (C) 2002, 2004-2006, 2009-2023 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -26,17 +26,24 @@ AC_DEFUN([gl_CHECK_FUNC_TIMESPEC_GET],
 
   dnl We can't use AC_CHECK_FUNC here, because timespec_get() is defined as a
   dnl static inline function in <time.h> on MSVC 14.
-  AC_CACHE_CHECK([for timespec_get], [gl_cv_func_timespec_get],
-    [AC_LINK_IFELSE(
-       [AC_LANG_PROGRAM(
-          [[#include <time.h>
-            struct timespec ts;
-          ]],
-          [[return timespec_get (&ts, 0);]])
-       ],
-       [gl_cv_func_timespec_get=yes],
-       [gl_cv_func_timespec_get=no])
-    ])
+  dnl But at the same time, we need to notice a missing declaration, like
+  dnl gl_CHECK_FUNCS_ANDROID does.
+  AC_CHECK_DECL([timespec_get], , , [[#include <time.h>]])
+  if test $ac_cv_have_decl_timespec_get = yes; then
+    AC_CACHE_CHECK([for timespec_get], [gl_cv_func_timespec_get],
+      [AC_LINK_IFELSE(
+         [AC_LANG_PROGRAM(
+            [[#include <time.h>
+              struct timespec ts;
+            ]],
+            [[return timespec_get (&ts, 0);]])
+         ],
+         [gl_cv_func_timespec_get=yes],
+         [gl_cv_func_timespec_get=no])
+      ])
+  else
+    gl_cv_func_timespec_get=no
+  fi
 ])
 
 AC_DEFUN([gl_GETTIME_RES],
diff --git a/m4/gnulib-common.m4 b/m4/gnulib-common.m4
index 26239caa2b..2db3376b01 100644
--- a/m4/gnulib-common.m4
+++ b/m4/gnulib-common.m4
@@ -71,7 +71,7 @@ AC_DEFUN([gl_COMMON_BODY], [
      && (!defined __clang_minor__ \
          || (defined __apple_build_version__ \
              ? 6000000 <= __apple_build_version__ \
-             : 3 < __clang_major__ + (5 <= __clang_minor__))))
+             : 5 <= __clang_major__)))
 # define _GL_HAS_ATTRIBUTE(attr) __has_attribute (__##attr##__)
 #else
 # define _GL_HAS_ATTRIBUTE(attr) _GL_ATTR_##attr
diff --git a/m4/gnulib-comp.m4 b/m4/gnulib-comp.m4
index ae5001c44b..10c74fa239 100644
--- a/m4/gnulib-comp.m4
+++ b/m4/gnulib-comp.m4
@@ -456,6 +456,14 @@ AC_DEFUN([gl_INIT],
     gl_PREREQ_PTHREAD_SIGMASK
   ])
   gl_SIGNAL_MODULE_INDICATOR([pthread_sigmask])
+  gl_FUNC_XATTR
+  AC_REQUIRE([gl_FUNC_ACL])
+  if test "$use_xattr" = yes; then
+    QCOPY_ACL_LIB="$LIB_XATTR"
+  else
+    QCOPY_ACL_LIB="$LIB_ACL"
+  fi
+  AC_SUBST([QCOPY_ACL_LIB])
   gl_FUNC_READLINK
   gl_CONDITIONAL([GL_COND_OBJ_READLINK],
                  [test $HAVE_READLINK = 0 || test $REPLACE_READLINK = 1])
@@ -1543,5 +1551,6 @@ AC_DEFUN([gl_FILE_LIST], [
   m4/warnings.m4
   m4/wchar_t.m4
   m4/wint_t.m4
+  m4/xattr.m4
   m4/zzgnulib.m4
 ])
diff --git a/m4/utimens.m4 b/m4/utimens.m4
index ae35ef789b..c5d9b69e6f 100644
--- a/m4/utimens.m4
+++ b/m4/utimens.m4
@@ -3,7 +3,7 @@ dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
 dnl with or without modifications, as long as this notice is preserved.
 
-dnl serial 11
+dnl serial 12
 
 AC_DEFUN([gl_UTIMENS],
 [
@@ -11,7 +11,9 @@ AC_DEFUN([gl_UTIMENS],
   AC_REQUIRE([gl_FUNC_UTIMES])
   AC_REQUIRE([gl_CHECK_TYPE_STRUCT_TIMESPEC])
   AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
-  AC_CHECK_FUNCS_ONCE([futimes futimesat futimens utimensat lutimes])
+  AC_CHECK_FUNCS_ONCE([futimens utimensat lutimes])
+  gl_CHECK_FUNCS_ANDROID([futimes], [[#include <sys/time.h>]])
+  gl_CHECK_FUNCS_ANDROID([futimesat], [[#include <sys/time.h>]])
 
   if test $ac_cv_func_futimens = no && test $ac_cv_func_futimesat = yes; then
     dnl FreeBSD 8.0-rc2 mishandles futimesat(fd,NULL,time).  It is not
diff --git a/m4/xattr.m4 b/m4/xattr.m4
new file mode 100644
index 0000000000..6141515652
--- /dev/null
+++ b/m4/xattr.m4
@@ -0,0 +1,43 @@
+# xattr.m4 - check for Extended Attributes (Linux)
+# serial 5
+
+# Copyright (C) 2003-2023 Free Software Foundation, Inc.
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_FUNC_XATTR],
+[
+  AC_ARG_ENABLE([xattr],
+        AS_HELP_STRING([--disable-xattr],
+                       [do not support extended attributes]),
+        [use_xattr=$enableval], [use_xattr=yes])
+
+  LIB_XATTR=
+  AC_SUBST([LIB_XATTR])
+
+  if test "$use_xattr" = yes; then
+    AC_CHECK_HEADERS([attr/error_context.h attr/libattr.h])
+    use_xattr=no
+    if test "$ac_cv_header_attr_libattr_h" = yes \
+        && test "$ac_cv_header_attr_error_context_h" = yes; then
+      xattr_saved_LIBS=$LIBS
+      AC_SEARCH_LIBS([attr_copy_file], [attr],
+                     [test "$ac_cv_search_attr_copy_file" = "none required" ||
+                        LIB_XATTR="$ac_cv_search_attr_copy_file"])
+      AC_CHECK_FUNCS([attr_copy_file])
+      LIBS=$xattr_saved_LIBS
+      if test "$ac_cv_func_attr_copy_file" = yes; then
+        use_xattr=yes
+      fi
+    fi
+    if test $use_xattr = no; then
+      AC_MSG_WARN([libattr development library was not found or not usable.])
+      AC_MSG_WARN([AC_PACKAGE_NAME will be built without xattr support.])
+    fi
+  fi
+  if test "$use_xattr" = yes; then
+    AC_DEFINE([USE_XATTR], [1],
+      [Define to 1 to use the Linux extended attributes library.])
+  fi
+])
diff --git a/msdos/sed1v2.inp b/msdos/sed1v2.inp
index ac7041a1be..162ccb3e8d 100644
--- a/msdos/sed1v2.inp
+++ b/msdos/sed1v2.inp
@@ -182,6 +182,7 @@ s/ *@WEBP_LIBS@//
 /^TREE_SITTER_CFLAGS *=/s/@TREE_SITTER_CFLAGS@//
 /^HARFBUZZ_CFLAGS *=/s/@HARFBUZZ_CFLAGS@//
 /^HARFBUZZ_LIBS *=/s/@HARFBUZZ_LIBS@//
+/^QCOPY_ACL_LIB *=/s/@QCOPY_ACL_LIB@//
 /^LCMS2_CFLAGS *=/s/@LCMS2_CFLAGS@//
 /^LCMS2_LIBS *=/s/@LCMS2_LIBS@//
 /^LIBGMP *=/s/@LIBGMP@//
diff --git a/src/Makefile.in b/src/Makefile.in
index 64bbde1a94..1b4a8a16c4 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -158,6 +158,7 @@ LIB_ACL=@LIB_ACL@
 CLOCK_TIME_LIB=@CLOCK_TIME_LIB@
 EUIDACCESS_LIBGEN=@EUIDACCESS_LIBGEN@
 NANOSLEEP_LIB=@NANOSLEEP_LIB@
+QCOPY_ACL_LIB=@QCOPY_ACL_LIB@
 LIB_TIMER_TIME=@LIB_TIMER_TIME@
 
 DBUS_CFLAGS = @DBUS_CFLAGS@
@@ -576,7 +577,7 @@ lisp = $(addprefix ${lispsource}/,${shortlisp})
 LIBES = $(LIBS) $(W32_LIBS) $(LIBS_GNUSTEP) $(PGTK_LIBS) $(LIBX_BASE) 
$(LIBIMAGE) \
    $(LIBX_OTHER) $(LIBSOUND) \
    $(RSVG_LIBS) $(IMAGEMAGICK_LIBS) $(LIB_ACL) $(CLOCK_TIME_LIB) \
-   $(NANOSLEEP_LIB) $(WEBKIT_LIBS) \
+   $(NANOSLEEP_LIB) $(QCOPY_ACL_LIB) $(WEBKIT_LIBS) \
    $(EUIDACCESS_LIBGEN) $(LIB_TIMER_TIME) $(DBUS_LIBS) \
    $(LIB_EXECINFO) $(XRANDR_LIBS) $(XINERAMA_LIBS) $(XFIXES_LIBS) \
    $(XDBE_LIBS) $(XSYNC_LIBS) \
diff --git a/src/coding.c b/src/coding.c
index 4e59f2b6a1..49dcd8634f 100644
--- a/src/coding.c
+++ b/src/coding.c
@@ -1431,7 +1431,7 @@ encode_coding_utf_8 (struct coding_system *coding)
   ptrdiff_t produced_chars = 0;
   int c;
 
-  if (CODING_UTF_8_BOM (coding) == utf_with_bom)
+  if (CODING_UTF_8_BOM (coding) != utf_without_bom)
     {
       ASSURE_DESTINATION (3);
       EMIT_THREE_BYTES (UTF_8_BOM_1, UTF_8_BOM_2, UTF_8_BOM_3);
diff --git a/src/fns.c b/src/fns.c
index 443e6e54f0..4ecd950b81 100644
--- a/src/fns.c
+++ b/src/fns.c
@@ -38,6 +38,10 @@ along with GNU Emacs.  If not, see 
<https://www.gnu.org/licenses/>.  */
 #include "puresize.h"
 #include "gnutls.h"
 
+#ifdef HAVE_TREE_SITTER
+#include "treesit.h"
+#endif
+
 enum equal_kind { EQUAL_NO_QUIT, EQUAL_PLAIN, EQUAL_INCLUDING_PROPERTIES };
 static bool internal_equal (Lisp_Object, Lisp_Object,
                            enum equal_kind, int, Lisp_Object);
@@ -2828,6 +2832,11 @@ internal_equal (Lisp_Object o1, Lisp_Object o2, enum 
equal_kind equal_kind,
                                bool_vector_bytes (size)));
          }
 
+#ifdef HAVE_TREE_SITTER
+       if (TS_NODEP (o1))
+         return treesit_node_eq (o1, o2);
+#endif
+
        /* Aside from them, only true vectors, char-tables, compiled
           functions, and fonts (font-spec, font-entity, font-object)
           are sensible to compare, so eliminate the others now.  */
diff --git a/src/pgtkterm.c b/src/pgtkterm.c
index 5158492ca0..c00e13550b 100644
--- a/src/pgtkterm.c
+++ b/src/pgtkterm.c
@@ -2959,7 +2959,8 @@ pgtk_draw_window_cursor (struct window *w, struct 
glyph_row *glyph_row, int x,
       if (w == XWINDOW (f->selected_window))
        {
          int frame_x = (WINDOW_TO_FRAME_PIXEL_X (w, x)
-                        + WINDOW_LEFT_FRINGE_WIDTH (w));
+                        + WINDOW_LEFT_FRINGE_WIDTH (w)
+                        + WINDOW_LEFT_MARGIN_WIDTH (w));
          int frame_y = WINDOW_TO_FRAME_PIXEL_Y (w, y);
          pgtk_im_set_cursor_location (f, frame_x, frame_y,
                                       w->phys_cursor_width,
diff --git a/src/treesit.c b/src/treesit.c
index 55463122d1..3886fed346 100644
--- a/src/treesit.c
+++ b/src/treesit.c
@@ -406,6 +406,24 @@ init_treesit_functions (void)
 
 /*** Initialization */
 
+static Lisp_Object Vtreesit_str_libtree_sitter;
+static Lisp_Object Vtreesit_str_tree_sitter;
+static Lisp_Object Vtreesit_str_dot;
+static Lisp_Object Vtreesit_str_question_mark;
+static Lisp_Object Vtreesit_str_star;
+static Lisp_Object Vtreesit_str_plus;
+static Lisp_Object Vtreesit_str_pound_equal;
+static Lisp_Object Vtreesit_str_pound_match;
+static Lisp_Object Vtreesit_str_pound_pred;
+static Lisp_Object Vtreesit_str_open_bracket;
+static Lisp_Object Vtreesit_str_close_bracket;
+static Lisp_Object Vtreesit_str_open_paren;
+static Lisp_Object Vtreesit_str_close_paren;
+static Lisp_Object Vtreesit_str_space;
+static Lisp_Object Vtreesit_str_equal;
+static Lisp_Object Vtreesit_str_match;
+static Lisp_Object Vtreesit_str_pred;
+
 /* This is the limit on recursion levels for some tree-sitter
    functions.  Remember to update docstrings when changing this
    value. */
@@ -534,9 +552,9 @@ treesit_load_language (Lisp_Object language_symbol,
 
   /* Figure out the library name and C name.  */
   Lisp_Object lib_base_name
-    = concat2 (build_pure_c_string ("libtree-sitter-"), symbol_name);
+    = concat2 (Vtreesit_str_libtree_sitter, symbol_name);
   Lisp_Object base_name
-    = concat2 (build_pure_c_string ("tree-sitter-"), symbol_name);
+    = concat2 (Vtreesit_str_tree_sitter, symbol_name);
 
   /* Override the library name and C name, if appropriate.  */
   Lisp_Object override_name;
@@ -945,7 +963,7 @@ treesit_check_buffer_size (struct buffer *buffer)
   ptrdiff_t buffer_size_bytes = (BUF_Z_BYTE (buffer) - BUF_BEG_BYTE (buffer));
   if (buffer_size_bytes > UINT32_MAX)
     xsignal2 (Qtreesit_buffer_too_large,
-             build_pure_c_string ("Buffer size cannot be larger than 4GB"),
+             build_string ("Buffer size cannot be larger than 4GB"),
              make_fixnum (buffer_size_bytes));
 }
 
@@ -1200,7 +1218,7 @@ treesit_compose_query_signal_data (uint32_t error_offset,
   return list4 (build_string (treesit_query_error_to_string (error_type)),
                make_fixnum (error_offset + 1),
                query_source,
-               build_pure_c_string ("Debug the query with 
`treesit-query-validate'"));
+               build_string ("Debug the query with `treesit-query-validate'"));
 }
 
 /* Ensure the QUERY is compiled.  Return the TSQuery.  It could be
@@ -1498,8 +1516,8 @@ treesit_check_range_argument (Lisp_Object ranges)
       EMACS_INT end = XFIXNUM (XCDR (range));
       if (!(last_point <= beg && beg <= end && end <= point_max))
        xsignal2 (Qtreesit_range_invalid,
-                 build_pure_c_string ("RANGE is either overlapping,"
-                                      " out-of-order or out-of-range"),
+                 build_string ("RANGE is either overlapping,"
+                               " out-of-order or out-of-range"),
                  ranges);
       last_point = end;
     }
@@ -1607,7 +1625,7 @@ buffer.  */)
 
   if (!success)
     xsignal2 (Qtreesit_range_invalid,
-             build_pure_c_string ("Something went wrong when setting ranges"),
+             build_string ("Something went wrong when setting ranges"),
              ranges);
 
   XTS_PARSER (parser)->need_reparse = true;
@@ -2154,11 +2172,24 @@ If NODE is nil, return nil.  */)
   return make_treesit_node (XTS_NODE (node)->parser, child);
 }
 
+/* Return true if NODE1 and NODE2 are the same node.  Assumes they are
+   TS_NODE type.  */
+bool treesit_node_eq (Lisp_Object node1, Lisp_Object node2)
+{
+  treesit_initialize ();
+  TSNode treesit_node_1 = XTS_NODE (node1)->node;
+  TSNode treesit_node_2 = XTS_NODE (node2)->node;
+  return ts_node_eq (treesit_node_1, treesit_node_2);
+}
+
 DEFUN ("treesit-node-eq",
        Ftreesit_node_eq,
        Streesit_node_eq, 2, 2, 0,
-       doc: /* Return non-nil if NODE1 and NODE2 are the same node.
-If any one of NODE1 and NODE2 is nil, return nil.  */)
+       doc: /* Return non-nil if NODE1 and NODE2 refer to the same node.
+If any one of NODE1 and NODE2 is nil, return nil.
+This function uses the same equivalence metric as `equal', and returns
+non-nil if NODE1 and NODE2 refer to the same node in a syntax tree
+produced by tree-sitter.  */)
   (Lisp_Object node1, Lisp_Object node2)
 {
   if (NILP (node1) || NILP (node2))
@@ -2166,12 +2197,7 @@ If any one of NODE1 and NODE2 is nil, return nil.  */)
   CHECK_TS_NODE (node1);
   CHECK_TS_NODE (node2);
 
-  treesit_initialize ();
-
-  TSNode treesit_node_1 = XTS_NODE (node1)->node;
-  TSNode treesit_node_2 = XTS_NODE (node2)->node;
-
-  bool same_node = ts_node_eq (treesit_node_1, treesit_node_2);
+  bool same_node = treesit_node_eq (node1, node2);
   return same_node ? Qt : Qnil;
 }
 
@@ -2202,30 +2228,32 @@ See Info node `(elisp)Pattern Matching' for detailed 
explanation.  */)
   (Lisp_Object pattern)
 {
   if (EQ (pattern, QCanchor))
-    return build_pure_c_string (".");
+    return Vtreesit_str_dot;
   if (EQ (pattern, intern_c_string (":?")))
-    return build_pure_c_string ("?");
+    return Vtreesit_str_question_mark;
   if (EQ (pattern, intern_c_string (":*")))
-    return build_pure_c_string ("*");
+    return Vtreesit_str_star;
   if (EQ (pattern, intern_c_string (":+")))
-    return build_pure_c_string ("+");
+    return Vtreesit_str_plus;
   if (EQ (pattern, QCequal))
-    return build_pure_c_string ("#equal");
+    return Vtreesit_str_pound_equal;
   if (EQ (pattern, QCmatch))
-    return build_pure_c_string ("#match");
+    return Vtreesit_str_pound_match;
   if (EQ (pattern, QCpred))
-    return build_pure_c_string ("#pred");
+    return Vtreesit_str_pound_pred;
   Lisp_Object opening_delimeter
-    = build_pure_c_string (VECTORP (pattern) ? "[" : "(");
+    = VECTORP (pattern)
+      ? Vtreesit_str_open_bracket : Vtreesit_str_open_paren;
   Lisp_Object closing_delimiter
-    = build_pure_c_string (VECTORP (pattern) ? "]" : ")");
+    = VECTORP (pattern)
+      ? Vtreesit_str_close_bracket : Vtreesit_str_close_paren;
   if (VECTORP (pattern) || CONSP (pattern))
     return concat3 (opening_delimeter,
                    Fmapconcat (Qtreesit_pattern_expand,
                                pattern,
-                               build_pure_c_string (" ")),
+                               Vtreesit_str_space),
                    closing_delimiter);
-  return CALLN (Fformat, build_pure_c_string ("%S"), pattern);
+  return Fprin1_to_string (pattern, Qnil, Qt);
 }
 
 DEFUN ("treesit-query-expand",
@@ -2252,8 +2280,7 @@ A PATTERN in QUERY can be
 See Info node `(elisp)Pattern Matching' for detailed explanation.  */)
   (Lisp_Object query)
 {
-  return Fmapconcat (Qtreesit_pattern_expand,
-                    query, build_pure_c_string (" "));
+  return Fmapconcat (Qtreesit_pattern_expand, query, Vtreesit_str_space);
 }
 
 /* This struct is used for passing captures to be check against
@@ -2333,10 +2360,10 @@ treesit_predicate_capture_name_to_node (Lisp_Object 
name,
 
   if (NILP (node))
     xsignal3 (Qtreesit_query_error,
-             build_pure_c_string ("Cannot find captured node"),
-             name, build_pure_c_string ("A predicate can only refer"
-                                        " to captured nodes in the "
-                                        "same pattern"));
+             build_string ("Cannot find captured node"),
+             name, build_string ("A predicate can only refer"
+                                 " to captured nodes in the "
+                                 "same pattern"));
   return node;
 }
 
@@ -2365,8 +2392,8 @@ treesit_predicate_equal (Lisp_Object args, struct 
capture_range captures)
 {
   if (XFIXNUM (Flength (args)) != 2)
     xsignal2 (Qtreesit_query_error,
-             build_pure_c_string ("Predicate `equal' requires "
-                                  "two arguments but only given"),
+             build_string ("Predicate `equal' requires "
+                           "two arguments but only given"),
              Flength (args));
 
   Lisp_Object arg1 = XCAR (args);
@@ -2391,8 +2418,8 @@ treesit_predicate_match (Lisp_Object args, struct 
capture_range captures)
 {
   if (XFIXNUM (Flength (args)) != 2)
     xsignal2 (Qtreesit_query_error,
-             build_pure_c_string ("Predicate `equal' requires two "
-                                  "arguments but only given"),
+             build_string ("Predicate `equal' requires two "
+                           "arguments but only given"),
              Flength (args));
 
   Lisp_Object regexp = XCAR (args);
@@ -2404,12 +2431,12 @@ treesit_predicate_match (Lisp_Object args, struct 
capture_range captures)
      string-match does.)  */
   if (!STRINGP (regexp))
     xsignal1 (Qtreesit_query_error,
-             build_pure_c_string ("The first argument to `match' should "
-                                  "be a regexp string, not a capture name"));
+             build_string ("The first argument to `match' should "
+                           "be a regexp string, not a capture name"));
   if (!SYMBOLP (capture_name))
     xsignal1 (Qtreesit_query_error,
-             build_pure_c_string ("The second argument to `match' should "
-                                  "be a capture name, not a string"));
+             build_string ("The second argument to `match' should "
+                           "be a capture name, not a string"));
 
   Lisp_Object text = treesit_predicate_capture_name_to_text (capture_name,
                                                             captures);
@@ -2428,9 +2455,9 @@ treesit_predicate_pred (Lisp_Object args, struct 
capture_range captures)
 {
   if (XFIXNUM (Flength (args)) < 2)
     xsignal2 (Qtreesit_query_error,
-             build_pure_c_string ("Predicate `pred' requires "
-                                  "at least two arguments, "
-                                  "but was only given"),
+             build_string ("Predicate `pred' requires "
+                           "at least two arguments, "
+                           "but was only given"),
              Flength (args));
 
   Lisp_Object fn = Fintern (XCAR (args), Qnil);
@@ -2458,18 +2485,18 @@ treesit_eval_predicates (struct capture_range captures, 
Lisp_Object predicates)
       Lisp_Object predicate = XCAR (tail);
       Lisp_Object fn = XCAR (predicate);
       Lisp_Object args = XCDR (predicate);
-      if (!NILP (Fstring_equal (fn, build_pure_c_string ("equal"))))
+      if (!NILP (Fstring_equal (fn, Vtreesit_str_equal)))
        pass &= treesit_predicate_equal (args, captures);
-      else if (!NILP (Fstring_equal (fn, build_pure_c_string ("match"))))
+      else if (!NILP (Fstring_equal (fn, Vtreesit_str_match)))
        pass &= treesit_predicate_match (args, captures);
-      else if (!NILP (Fstring_equal (fn, build_pure_c_string ("pred"))))
+      else if (!NILP (Fstring_equal (fn, Vtreesit_str_pred)))
        pass &= treesit_predicate_pred (args, captures);
       else
        xsignal3 (Qtreesit_query_error,
-                 build_pure_c_string ("Invalid predicate"),
-                 fn, build_pure_c_string ("Currently Emacs only supports"
-                                          " equal, match, and pred"
-                                          " predicate"));
+                 build_string ("Invalid predicate"),
+                 fn, build_string ("Currently Emacs only supports"
+                                   " equal, match, and pred"
+                                   " predicate"));
     }
   /* If all predicates passed, add captures to result list.  */
   return pass;
@@ -3369,6 +3396,41 @@ then in the `tree-sitter' subdirectory of 
`user-emacs-directory', and
 then in the system default locations for dynamic libraries, in that order.  
*/);
   Vtreesit_extra_load_path = Qnil;
 
+  staticpro (&Vtreesit_str_libtree_sitter);
+  Vtreesit_str_libtree_sitter = build_pure_c_string ("libtree-sitter-");
+  staticpro (&Vtreesit_str_tree_sitter);
+  Vtreesit_str_tree_sitter = build_pure_c_string ("tree-sitter-");
+  staticpro (&Vtreesit_str_dot);
+  Vtreesit_str_dot = build_pure_c_string (".");
+  staticpro (&Vtreesit_str_question_mark);
+  Vtreesit_str_question_mark = build_pure_c_string ("?");
+  staticpro (&Vtreesit_str_star);
+  Vtreesit_str_star = build_pure_c_string ("*");
+  staticpro (&Vtreesit_str_plus);
+  Vtreesit_str_plus = build_pure_c_string ("+");
+  staticpro (&Vtreesit_str_pound_equal);
+  Vtreesit_str_pound_equal = build_pure_c_string ("#equal");
+  staticpro (&Vtreesit_str_pound_match);
+  Vtreesit_str_pound_match = build_pure_c_string ("#match");
+  staticpro (&Vtreesit_str_pound_pred);
+  Vtreesit_str_pound_pred = build_pure_c_string ("#pred");
+  staticpro (&Vtreesit_str_open_bracket);
+  Vtreesit_str_open_bracket = build_pure_c_string ("[");
+  staticpro (&Vtreesit_str_close_bracket);
+  Vtreesit_str_close_bracket = build_pure_c_string ("]");
+  staticpro (&Vtreesit_str_open_paren);
+  Vtreesit_str_open_paren = build_pure_c_string ("(");
+  staticpro (&Vtreesit_str_close_paren);
+  Vtreesit_str_close_paren = build_pure_c_string (")");
+  staticpro (&Vtreesit_str_space);
+  Vtreesit_str_space = build_pure_c_string (" ");
+  staticpro (&Vtreesit_str_equal);
+  Vtreesit_str_equal = build_pure_c_string ("equal");
+  staticpro (&Vtreesit_str_match);
+  Vtreesit_str_match = build_pure_c_string ("match");
+  staticpro (&Vtreesit_str_pred);
+  Vtreesit_str_pred = build_pure_c_string ("pred");
+
   defsubr (&Streesit_language_available_p);
   defsubr (&Streesit_library_abi_version);
   defsubr (&Streesit_language_abi_version);
diff --git a/src/treesit.h b/src/treesit.h
index 909609737d..5382bc5881 100644
--- a/src/treesit.h
+++ b/src/treesit.h
@@ -191,6 +191,7 @@ extern bool treesit_node_uptodate_p (Lisp_Object);
 extern void treesit_delete_parser (struct Lisp_TS_Parser *);
 extern void treesit_delete_query (struct Lisp_TS_Query *);
 extern bool treesit_named_node_p (TSNode);
+extern bool treesit_node_eq (Lisp_Object, Lisp_Object);
 
 #endif /* HAVE_TREE_SITTER */
 
diff --git a/test/lisp/eshell/em-prompt-tests.el 
b/test/lisp/eshell/em-prompt-tests.el
new file mode 100644
index 0000000000..91464a98c2
--- /dev/null
+++ b/test/lisp/eshell/em-prompt-tests.el
@@ -0,0 +1,118 @@
+;;; em-prompt-tests.el --- em-prompt test suite  -*- lexical-binding:t -*-
+
+;; Copyright (C) 2023 Free Software Foundation, Inc.
+
+;; 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/>.
+
+;;; Commentary:
+
+;; Tests for Eshell's prompt support.
+
+;;; Code:
+
+(require 'ert)
+(require 'eshell)
+(require 'em-prompt)
+
+(require 'eshell-tests-helpers
+         (expand-file-name "eshell-tests-helpers"
+                           (file-name-directory (or load-file-name
+                                                    default-directory))))
+
+;;; Tests:
+
+(ert-deftest em-prompt-test/field-properties ()
+  "Check that field properties are properly set on Eshell output/prompts."
+  (with-temp-eshell
+   (eshell-insert-command "echo hello")
+   (let ((last-prompt (field-string (1- eshell-last-input-start)))
+         (last-input  (field-string (1+ eshell-last-input-start)))
+         (last-output (field-string (1+ eshell-last-input-end))))
+     (should (equal-including-properties
+              last-prompt
+              (propertize
+               (format "%s $ " (directory-file-name default-directory))
+               'read-only t
+               'field 'prompt
+               'font-lock-face 'eshell-prompt
+               'front-sticky '(read-only field font-lock-face)
+               'rear-nonsticky '(read-only field font-lock-face))))
+     (should (equal last-input "echo hello\n"))
+     (should (equal-including-properties
+              last-output
+              (propertize "hello\n" 'rear-nonsticky '(field)
+                          'field 'command-output))))))
+
+(ert-deftest em-prompt-test/field-properties/no-highlight ()
+  "Check that field properties are properly set on Eshell output/prompts.
+This tests the case when `eshell-highlight-prompt' is nil."
+  (let ((eshell-highlight-prompt nil))
+    (with-temp-eshell
+     (eshell-insert-command "echo hello")
+     (let ((last-prompt (field-string (1- eshell-last-input-start)))
+           (last-input  (field-string (1+ eshell-last-input-start)))
+           (last-output (field-string (1+ eshell-last-input-end))))
+       (should (equal-including-properties
+                last-prompt
+                (propertize
+                 (format "%s $ " (directory-file-name default-directory))
+                 'field 'prompt
+                 'front-sticky '(field)
+                 'rear-nonsticky '(field))))
+       (should (equal last-input "echo hello\n"))
+       (should (equal-including-properties
+                last-output
+                (propertize "hello\n" 'rear-nonsticky '(field)
+                            'field 'command-output)))))))
+
+(ert-deftest em-prompt-test/next-previous-prompt ()
+  "Check that navigating forward/backward through old prompts works correctly."
+  (with-temp-eshell
+   (eshell-insert-command "echo one")
+   (eshell-insert-command "echo two")
+   (eshell-insert-command "echo three")
+   (insert "echo fou")                  ; A partially-entered command.
+   ;; Go back one prompt.
+   (eshell-previous-prompt 1)
+   (should (equal (eshell-get-old-input) "echo three"))
+   ;; Go back two prompts, starting from the end of this line.
+   (end-of-line)
+   (eshell-previous-prompt 2)
+   (should (equal (eshell-get-old-input) "echo one"))
+   ;; Go forward three prompts.
+   (eshell-next-prompt 3)
+   (should (equal (eshell-get-old-input) "echo fou"))))
+
+(ert-deftest em-prompt-test/forward-backward-matching-input ()
+  "Check that navigating forward/backward via regexps works correctly."
+  (with-temp-eshell
+   (eshell-insert-command "echo one")
+   (eshell-insert-command "printnl something else")
+   (eshell-insert-command "echo two")
+   (eshell-insert-command "echo three")
+   (insert "echo fou")                  ; A partially-entered command.
+   ;; Go back one prompt.
+   (eshell-backward-matching-input "echo" 1)
+   (should (equal (eshell-get-old-input) "echo three"))
+   ;; Go back two prompts, starting from the end of this line.
+   (end-of-line)
+   (eshell-backward-matching-input "echo" 2)
+   (should (equal (eshell-get-old-input) "echo one"))
+   ;; Go forward three prompts.
+   (eshell-forward-matching-input "echo" 3)
+   (should (equal (eshell-get-old-input) "echo fou"))))
+
+;;; em-prompt-tests.el ends here
diff --git a/test/lisp/eshell/eshell-tests.el b/test/lisp/eshell/eshell-tests.el
index be968e1558..776cfb9b92 100644
--- a/test/lisp/eshell/eshell-tests.el
+++ b/test/lisp/eshell/eshell-tests.el
@@ -117,14 +117,14 @@
   (with-temp-eshell
    (eshell-insert-command "echo $(+ 1 (- 4 3)) \"alpha beta\" file" 'ignore)
    (let ((here (point)) begin valid)
-     (eshell-bol)
+     (beginning-of-line)
      (setq begin (point))
      (eshell-forward-argument 4)
      (setq valid (= here (point)))
      (eshell-backward-argument 4)
      (prog1
          (and valid (= begin (point)))
-       (eshell-bol)
+       (beginning-of-line)
        (delete-region (point) (point-max))))))
 
 (ert-deftest eshell-test/queue-input ()
@@ -148,12 +148,17 @@ insert the queued one at the next prompt, and finally run 
it."
    (should (eshell-match-output
             (concat "^" (regexp-quote "*** output flushed ***\n") "$")))))
 
-(ert-deftest eshell-test/run-old-command ()
-  "Re-run an old command"
+(ert-deftest eshell-test/get-old-input ()
+  "Test that we can get the input of a previous command."
   (with-temp-eshell
    (eshell-insert-command "echo alpha")
    (goto-char eshell-last-input-start)
-   (string= (eshell-get-old-input) "echo alpha")))
+   (should (string= (eshell-get-old-input) "echo alpha"))
+   ;; Make sure that `eshell-get-old-input' works even if the point is
+   ;; inside the prompt.
+   (let ((inhibit-field-text-motion t))
+     (beginning-of-line))
+   (should (string= (eshell-get-old-input) "echo alpha"))))
 
 (provide 'eshell-tests)
 
diff --git a/test/lisp/minibuffer-tests.el b/test/lisp/minibuffer-tests.el
index 1de8e56cbd..2ac5e0f29d 100644
--- a/test/lisp/minibuffer-tests.el
+++ b/test/lisp/minibuffer-tests.el
@@ -421,7 +421,7 @@
       (switch-to-completions)
       ;; Fixed in bug#55430
       (should (equal "aa" (get-text-property (point) 'completion--string)))
-      (next-completion 2)
+      (next-completion 3)
       (should (equal "ac" (get-text-property (point) 'completion--string)))
       (previous-completion 2)
       (should (equal "aa" (get-text-property (point) 'completion--string)))
diff --git a/test/lisp/proced-tests.el b/test/lisp/proced-tests.el
index 3c1f5493e7..1f47566529 100644
--- a/test/lisp/proced-tests.el
+++ b/test/lisp/proced-tests.el
@@ -101,5 +101,22 @@
        (should (string= pid (word-at-point)))
        (forward-line)))))
 
+(ert-deftest proced-update-preserves-pid-at-point-test ()
+  (proced--within-buffer
+   'medium
+   'user
+   (goto-char (point-min))
+   (search-forward (number-to-string (emacs-pid)))
+   (proced--move-to-column "PID")
+   (save-window-excursion
+     (let ((pid (proced-pid-at-point))
+           (new-window (split-window))
+           (old-window (get-buffer-window)))
+       (select-window new-window)
+       (with-current-buffer "*Proced*"
+         (proced-update t t))
+       (select-window old-window)
+       (should (= pid (proced-pid-at-point)))))))
+
 (provide 'proced-tests)
 ;;; proced-tests.el ends here
diff --git a/test/lisp/progmodes/c-ts-mode-resources/indent.erts 
b/test/lisp/progmodes/c-ts-mode-resources/indent.erts
new file mode 100644
index 0000000000..5defcbd3c8
--- /dev/null
+++ b/test/lisp/progmodes/c-ts-mode-resources/indent.erts
@@ -0,0 +1,44 @@
+Code:
+  (lambda ()
+    (c-ts-mode)
+    (indent-region (point-min) (point-max)))
+
+Name: Basic
+
+=-=
+int
+main (void)
+{
+  return 0;
+}
+=-=-=
+
+Name: Hanging Braces (GNU Style)
+
+=-=
+int
+main (void)
+{
+  if (true)
+    {
+    }
+}
+=-=-=
+
+Name: Multiline Parameter List (bug#60398)
+
+=-=
+int f2(int x,
+       int y) {
+  return x + y;
+};
+=-=-=
+
+Name: Multiline Block Comments (bug#60270)
+
+=-=
+/**
+ * @some_func:
+ * @arg1:
+ */
+=-=-=
diff --git a/test/lisp/progmodes/c-ts-mode-tests.el 
b/test/lisp/progmodes/c-ts-mode-tests.el
new file mode 100644
index 0000000000..8606faf991
--- /dev/null
+++ b/test/lisp/progmodes/c-ts-mode-tests.el
@@ -0,0 +1,31 @@
+;;; c-ts-mode-tests.el --- Tests for Tree-sitter-based C mode         -*- 
lexical-binding: t; -*-
+
+;; Copyright (C) 2023 Free Software Foundation, Inc.
+
+;; 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)
+(require 'ert-x)
+(require 'treesit)
+
+(ert-deftest c-ts-mode-test-indentation ()
+  (skip-unless (treesit-ready-p 'c))
+  (ert-test-erts-file (ert-resource-file "indent.erts")))
+
+(provide 'c-ts-mode-tests)
+;;; c-ts-mode-tests.el ends here
diff --git a/test/src/coding-tests.el b/test/src/coding-tests.el
index 6bd8d1ae6c..b27907027b 100644
--- a/test/src/coding-tests.el
+++ b/test/src/coding-tests.el
@@ -148,21 +148,21 @@
 
 (defun coding-tests (content-type write-coding read-coding detected-coding
                                   &optional translator)
-  (prefer-coding-system 'utf-8-auto)
-  (let ((filename (coding-tests-filename content-type write-coding)))
-    (with-temp-buffer
-      (let ((coding-system-for-read read-coding)
-           (contents (coding-tests-file-contents content-type))
-           (disable-ascii-optimization nil))
-       (if translator
-           (setq contents (funcall translator contents)))
-       (insert-file-contents filename)
-       (if (and (coding-system-equal buffer-file-coding-system detected-coding)
-                (string= (buffer-string) contents))
-           nil
-         (list buffer-file-coding-system
-               (string-to-list (buffer-string))
-               (string-to-list contents)))))))
+  (with-coding-priority '(utf-8-auto)
+    (let ((filename (coding-tests-filename content-type write-coding)))
+      (with-temp-buffer
+        (let ((coding-system-for-read read-coding)
+             (contents (coding-tests-file-contents content-type))
+             (disable-ascii-optimization nil))
+         (if translator
+             (setq contents (funcall translator contents)))
+         (insert-file-contents filename)
+         (if (and (coding-system-equal buffer-file-coding-system 
detected-coding)
+                  (string= (buffer-string) contents))
+             nil
+           (list buffer-file-coding-system
+                 (string-to-list (buffer-string))
+                 (string-to-list contents))))))))
 
 (ert-deftest ert-test-coding-ascii ()
   (unwind-protect



reply via email to

[Prev in Thread] Current Thread [Next in Thread]