emacs-diffs
[Top][All Lists]
Advanced

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

feature/android 6253e7e742 3/3: Merge remote-tracking branch 'origin/mas


From: Po Lu
Subject: feature/android 6253e7e742 3/3: Merge remote-tracking branch 'origin/master' into feature/android
Date: Tue, 17 Jan 2023 09:12:03 -0500 (EST)

branch: feature/android
commit 6253e7e74249c7cdfa86723f0b91a1d207cb143e
Merge: 1b8258a1f2 96015c9c8c
Author: Po Lu <luangruo@yahoo.com>
Commit: Po Lu <luangruo@yahoo.com>

    Merge remote-tracking branch 'origin/master' into feature/android
---
 doc/lispref/files.texi                             |   6 +-
 doc/lispref/os.texi                                |  10 ++
 doc/misc/eshell.texi                               |   8 +
 etc/NEWS                                           |   6 +
 lisp/emacs-lisp/byte-opt.el                        |   3 +
 lisp/emacs-lisp/bytecomp.el                        |   2 +-
 lisp/eshell/em-prompt.el                           |   2 +-
 lisp/eshell/esh-var.el                             |   1 +
 lisp/htmlfontify.el                                |  14 +-
 lisp/net/tramp-adb.el                              |   1 +
 lisp/net/tramp-archive.el                          |   7 +
 lisp/net/tramp-crypt.el                            |   1 +
 lisp/net/tramp-gvfs.el                             |   1 +
 lisp/net/tramp-rclone.el                           |   1 +
 lisp/net/tramp-sh.el                               |   1 +
 lisp/net/tramp-smb.el                              |   1 +
 lisp/net/tramp-sshfs.el                            |   1 +
 lisp/net/tramp-sudoedit.el                         |   1 +
 lisp/net/tramp.el                                  |  13 +-
 lisp/progmodes/cc-engine.el                        |   8 +-
 lisp/progmodes/dockerfile-ts-mode.el               |   4 +
 lisp/progmodes/eglot.el                            |  24 +--
 lisp/progmodes/js.el                               |  15 +-
 lisp/progmodes/json-ts-mode.el                     |   2 +
 lisp/progmodes/ruby-ts-mode.el                     |  32 +++-
 lisp/progmodes/typescript-ts-mode.el               |  14 +-
 lisp/simple.el                                     |  12 ++
 lisp/subr.el                                       |   6 +-
 lisp/treesit.el                                    |   1 -
 lisp/use-package/use-package-core.el               |   2 +-
 lisp/use-package/use-package.el                    |   2 +-
 src/w32fns.c                                       |  16 +-
 src/xterm.c                                        | 188 ++++++++++++++++++++-
 src/xterm.h                                        |  17 ++
 test/lisp/eshell/esh-var-tests.el                  |   4 +
 .../lisp/progmodes/c-ts-mode-resources/indent.erts |  14 ++
 .../progmodes/java-ts-mode-resources/indent.erts   |  44 +++++
 .../progmodes/java-ts-mode-resources/movement.erts | 154 +++++++++++++++++
 test/lisp/progmodes/java-ts-mode-tests.el          |  35 ++++
 test/lisp/progmodes/ruby-ts-mode-tests.el          |   1 +
 .../typescript-ts-mode-resources/indent.erts       |  73 ++++++++
 test/lisp/progmodes/typescript-ts-mode-tests.el    |  31 ++++
 42 files changed, 714 insertions(+), 65 deletions(-)

diff --git a/doc/lispref/files.texi b/doc/lispref/files.texi
index 5cc4c1e7dd..ad01e0f288 100644
--- a/doc/lispref/files.texi
+++ b/doc/lispref/files.texi
@@ -3390,7 +3390,8 @@ first, before handlers for jobs such as remote file 
access.
 @code{file-readable-p}, @code{file-regular-p},
 @code{file-remote-p}, @code{file-selinux-context},
 @code{file-symlink-p}, @code{file-system-info},
-@code{file-truename}, @code{file-writable-p},
+@code{file-truename}, @code{file-user-uid},
+@code{file-writable-p},
 @code{find-backup-file-name},@*
 @code{get-file-buffer},
 @code{insert-directory},
@@ -3451,7 +3452,8 @@ first, before handlers for jobs such as remote file 
access.
 @code{file-readable-p}, @code{file-regular-p},
 @code{file-remote-p}, @code{file-selinux-context},
 @code{file-symlink-p}, @code{file-system-info},
-@code{file-truename}, @code{file-writable-p},
+@code{file-truename}, @code{file-user-uid},
+@code{file-writable-p},
 @code{find-backup-file-name},
 @code{get-file-buffer},
 @code{insert-directory},
diff --git a/doc/lispref/os.texi b/doc/lispref/os.texi
index 094e954e82..53ca128582 100644
--- a/doc/lispref/os.texi
+++ b/doc/lispref/os.texi
@@ -1280,6 +1280,16 @@ This function returns the real @acronym{UID} of the user.
 This function returns the effective @acronym{UID} of the user.
 @end defun
 
+@defun file-user-uid
+This function returns the connection-local value for the user's
+effective @acronym{UID}.  If @code{default-directory} is local, this
+is equivalent to @code{user-uid}, but for remote files (@pxref{Remote
+Files, , , emacs, The GNU Emacs Manual}), it will return the
+@acronym{UID} for the user associated with that remote connection; if
+the remote connection has no associated user, it will instead return
+-1.
+@end defun
+
 @cindex GID
 @defun group-gid
 This function returns the effective @acronym{GID} of the Emacs process.
diff --git a/doc/misc/eshell.texi b/doc/misc/eshell.texi
index fc7d52eb71..c40ff58f42 100644
--- a/doc/misc/eshell.texi
+++ b/doc/misc/eshell.texi
@@ -983,6 +983,13 @@ whenever you change the current directory to a different 
host
 the value will automatically update to reflect the search path on that
 host.
 
+@vindex $UID
+@item $UID
+This returns the effective @acronym{UID} for the current user.  This
+variable is connection-aware, so when the current directory is remote,
+its value will be @acronym{UID} for the user associated with that
+remote connection.
+
 @vindex $_
 @item $_
 This refers to the last argument of the last command.  With a
@@ -1014,6 +1021,7 @@ that are currently visible in the Eshell window.  They 
are both
 copied to the environment, so external commands invoked from
 Eshell can consult them to do the right thing.
 
+@vindex $INSIDE_EMACS
 @item $INSIDE_EMACS
 This variable indicates to external commands that they are being
 invoked from within Emacs so they can adjust their behavior if
diff --git a/etc/NEWS b/etc/NEWS
index 068f7a27db..cde6783349 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -235,6 +235,12 @@ compared reliably at all.
 This warning can be suppressed using 'with-suppressed-warnings' with
 the warning name 'suspicious'.
 
++++
+** New function 'file-user-uid'.
+This function is like 'user-uid', but is aware of file name handlers,
+so it will return the remote UID for remote files (or -1 if the
+connection has no associated user).
+
 
 * Changes in Emacs 30.1 on Non-Free Operating Systems
 
diff --git a/lisp/emacs-lisp/byte-opt.el b/lisp/emacs-lisp/byte-opt.el
index d7a0d851e0..039cebedb4 100644
--- a/lisp/emacs-lisp/byte-opt.el
+++ b/lisp/emacs-lisp/byte-opt.el
@@ -1380,6 +1380,9 @@ See Info node `(elisp) Integer Basics'."
            ;; (apply F ... (list X Y ...)) -> (funcall F ... X Y ...)
            ((eq (car-safe last) 'list)
             `(funcall ,fn ,@(butlast (cddr form)) ,@(cdr last)))
+           ;; (apply F ... (cons X Y)) -> (apply F ... X Y)
+           ((eq (car-safe last) 'cons)
+            (append (butlast form) (cdr last)))
            (t form)))
       form)))
 
diff --git a/lisp/emacs-lisp/bytecomp.el b/lisp/emacs-lisp/bytecomp.el
index 23d02ba92c..fb4b73b1c1 100644
--- a/lisp/emacs-lisp/bytecomp.el
+++ b/lisp/emacs-lisp/bytecomp.el
@@ -1575,7 +1575,7 @@ extra args."
         "`%s' called with %d args to fill %d format field(s)" (car form)
         nargs nfields)))))
 
-(dolist (elt '(format message error))
+(dolist (elt '(format message format-message error))
   (put elt 'byte-compile-format-like t))
 
 (defun byte-compile--suspicious-defcustom-choice (type)
diff --git a/lisp/eshell/em-prompt.el b/lisp/eshell/em-prompt.el
index 52d46282c5..b3a0fadf61 100644
--- a/lisp/eshell/em-prompt.el
+++ b/lisp/eshell/em-prompt.el
@@ -52,7 +52,7 @@ as is common with most shells."
 (defcustom eshell-prompt-function
   (lambda ()
     (concat (abbreviate-file-name (eshell/pwd))
-            (if (= (user-uid) 0) " # " " $ ")))
+            (if (= (file-user-uid) 0) " # " " $ ")))
   "A function that returns the Eshell prompt string.
 Make sure to update `eshell-prompt-regexp' so that it will match your
 prompt."
diff --git a/lisp/eshell/esh-var.el b/lisp/eshell/esh-var.el
index 811bb9957c..fd76a2c6f0 100644
--- a/lisp/eshell/esh-var.el
+++ b/lisp/eshell/esh-var.el
@@ -162,6 +162,7 @@ if they are quoted with a backslash."
     ("COLUMNS" ,(lambda () (window-body-width nil 'remap)) t t)
     ("LINES" ,(lambda () (window-body-height nil 'remap)) t t)
     ("INSIDE_EMACS" eshell-inside-emacs t)
+    ("UID" ,(lambda () (file-user-uid)) nil t)
 
     ;; for esh-ext.el
     ("PATH" (,(lambda () (string-join (eshell-get-path t) (path-separator)))
diff --git a/lisp/htmlfontify.el b/lisp/htmlfontify.el
index 0959405081..1ab33cc641 100644
--- a/lisp/htmlfontify.el
+++ b/lisp/htmlfontify.el
@@ -373,13 +373,13 @@ otherwise."
   :type  '(string))
 
 (defcustom hfy-exclude-file-rules
-  '("\\.flc$"
-    "/CVS/.*"
-    ".*~$"
-    "/\\.git\\(?:/.*\\)?$")
-  "Define some regular expressions to exclude files"
+  '("\\.flc\\'"
+    "/CVS/"
+    "~\\'"
+    "/\\.git\\(?:/\\|\\'\\)")
+  "Regular expressions matching files to exclude."
   :tag "exclude-rules"
-  :type '(list string)
+  :type '(repeat regexp)
   :version "29.1")
 
 (defcustom hfy-display-class nil
@@ -1835,7 +1835,7 @@ Strips any leading \"./\" from each filename."
                       (seq-some (lambda (r)
                                   (string-match r f))
                                 hfy-exclude-file-rules)))
-                (directory-files-recursively "." ".*" nil t)))
+                (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/net/tramp-adb.el b/lisp/net/tramp-adb.el
index 29b9f894ec..10f33e5f92 100644
--- a/lisp/net/tramp-adb.el
+++ b/lisp/net/tramp-adb.el
@@ -153,6 +153,7 @@ It is used for TCP/IP devices."
     (file-symlink-p . tramp-handle-file-symlink-p)
     (file-system-info . tramp-adb-handle-file-system-info)
     (file-truename . tramp-handle-file-truename)
+    (file-user-uid . tramp-handle-file-user-uid)
     (file-writable-p . tramp-adb-handle-file-writable-p)
     (find-backup-file-name . tramp-handle-find-backup-file-name)
     ;; `get-file-buffer' performed by default handler.
diff --git a/lisp/net/tramp-archive.el b/lisp/net/tramp-archive.el
index 3b1d568c12..b9cf85bd84 100644
--- a/lisp/net/tramp-archive.el
+++ b/lisp/net/tramp-archive.el
@@ -265,6 +265,7 @@ It must be supported by libarchive(3).")
     (file-symlink-p . tramp-handle-file-symlink-p)
     (file-system-info . tramp-archive-handle-file-system-info)
     (file-truename . tramp-archive-handle-file-truename)
+    (file-user-uid . tramp-archive-handle-file-user-uid)
     (file-writable-p . ignore)
     (find-backup-file-name . ignore)
     ;; `get-file-buffer' performed by default handler.
@@ -701,6 +702,12 @@ offered."
     (let ((default-directory (file-name-directory archive)))
       (temporary-file-directory))))
 
+(defun tramp-archive-handle-file-user-uid ()
+  "Like `user-uid' for file archives."
+  (with-parsed-tramp-archive-file-name default-directory nil
+    (let ((default-directory (file-name-directory archive)))
+      (file-user-uid))))
+
 (defun tramp-archive-handle-not-implemented (operation &rest args)
   "Generic handler for operations not implemented for file archives."
   (let ((v (ignore-errors
diff --git a/lisp/net/tramp-crypt.el b/lisp/net/tramp-crypt.el
index 507fd43241..b9d0d96ecc 100644
--- a/lisp/net/tramp-crypt.el
+++ b/lisp/net/tramp-crypt.el
@@ -204,6 +204,7 @@ If NAME doesn't belong to an encrypted remote directory, 
return nil."
     (file-symlink-p . tramp-handle-file-symlink-p)
     (file-system-info . tramp-crypt-handle-file-system-info)
     ;; `file-truename' performed by default handler.
+    (file-user-uid . tramp-handle-file-user-uid)
     (file-writable-p . tramp-crypt-handle-file-writable-p)
     (find-backup-file-name . tramp-handle-find-backup-file-name)
     ;; `get-file-buffer' performed by default handler.
diff --git a/lisp/net/tramp-gvfs.el b/lisp/net/tramp-gvfs.el
index ea774d0b9b..02ceb2979f 100644
--- a/lisp/net/tramp-gvfs.el
+++ b/lisp/net/tramp-gvfs.el
@@ -798,6 +798,7 @@ It has been changed in GVFS 1.14.")
     (file-symlink-p . tramp-handle-file-symlink-p)
     (file-system-info . tramp-gvfs-handle-file-system-info)
     (file-truename . tramp-handle-file-truename)
+    (file-user-uid . tramp-handle-file-user-uid)
     (file-writable-p . tramp-handle-file-writable-p)
     (find-backup-file-name . tramp-handle-find-backup-file-name)
     ;; `get-file-buffer' performed by default handler.
diff --git a/lisp/net/tramp-rclone.el b/lisp/net/tramp-rclone.el
index b28f9f6495..9eb2a54cdc 100644
--- a/lisp/net/tramp-rclone.el
+++ b/lisp/net/tramp-rclone.el
@@ -118,6 +118,7 @@
     (file-symlink-p . tramp-handle-file-symlink-p)
     (file-system-info . tramp-rclone-handle-file-system-info)
     (file-truename . tramp-handle-file-truename)
+    (file-user-uid . tramp-handle-file-user-uid)
     (file-writable-p . tramp-handle-file-writable-p)
     (find-backup-file-name . tramp-handle-find-backup-file-name)
     ;; `get-file-buffer' performed by default handler.
diff --git a/lisp/net/tramp-sh.el b/lisp/net/tramp-sh.el
index acbb6aea13..46b1f61210 100644
--- a/lisp/net/tramp-sh.el
+++ b/lisp/net/tramp-sh.el
@@ -1086,6 +1086,7 @@ Format specifiers \"%s\" are replaced before the script 
is used.")
     (file-symlink-p . tramp-handle-file-symlink-p)
     (file-system-info . tramp-sh-handle-file-system-info)
     (file-truename . tramp-sh-handle-file-truename)
+    (file-user-uid . tramp-handle-file-user-uid)
     (file-writable-p . tramp-sh-handle-file-writable-p)
     (find-backup-file-name . tramp-handle-find-backup-file-name)
     ;; `get-file-buffer' performed by default handler.
diff --git a/lisp/net/tramp-smb.el b/lisp/net/tramp-smb.el
index b3f0344f81..9d03490f1d 100644
--- a/lisp/net/tramp-smb.el
+++ b/lisp/net/tramp-smb.el
@@ -269,6 +269,7 @@ See `tramp-actions-before-shell' for more info.")
     (file-symlink-p . tramp-handle-file-symlink-p)
     (file-system-info . tramp-smb-handle-file-system-info)
     (file-truename . tramp-handle-file-truename)
+    (file-user-uid . tramp-handle-file-user-uid)
     (file-writable-p . tramp-smb-handle-file-writable-p)
     (find-backup-file-name . tramp-handle-find-backup-file-name)
     ;; `get-file-buffer' performed by default handler.
diff --git a/lisp/net/tramp-sshfs.el b/lisp/net/tramp-sshfs.el
index 27b2854e45..65c4bf23c3 100644
--- a/lisp/net/tramp-sshfs.el
+++ b/lisp/net/tramp-sshfs.el
@@ -124,6 +124,7 @@
     (file-symlink-p . tramp-handle-file-symlink-p)
     (file-system-info . tramp-sshfs-handle-file-system-info)
     (file-truename . tramp-handle-file-truename)
+    (file-user-uid . tramp-handle-file-user-uid)
     (file-writable-p . tramp-sshfs-handle-file-writable-p)
     (find-backup-file-name . tramp-handle-find-backup-file-name)
     ;; `get-file-buffer' performed by default handler.
diff --git a/lisp/net/tramp-sudoedit.el b/lisp/net/tramp-sudoedit.el
index ce080918e0..db7ac84287 100644
--- a/lisp/net/tramp-sudoedit.el
+++ b/lisp/net/tramp-sudoedit.el
@@ -114,6 +114,7 @@ See `tramp-actions-before-shell' for more info.")
     (file-symlink-p . tramp-handle-file-symlink-p)
     (file-system-info . tramp-sudoedit-handle-file-system-info)
     (file-truename . tramp-sudoedit-handle-file-truename)
+    (file-user-uid . tramp-handle-file-user-uid)
     (file-writable-p . tramp-sudoedit-handle-file-writable-p)
     (find-backup-file-name . tramp-handle-find-backup-file-name)
     ;; `get-file-buffer' performed by default handler.
diff --git a/lisp/net/tramp.el b/lisp/net/tramp.el
index 169cf1982b..fab1962d2b 100644
--- a/lisp/net/tramp.el
+++ b/lisp/net/tramp.el
@@ -2632,7 +2632,9 @@ Must be handled by the callers."
            '(exec-path make-nearby-temp-file make-process process-file
              shell-command start-file-process temporary-file-directory
              ;; Emacs 29+ only.
-              list-system-processes memory-info process-attributes))
+              list-system-processes memory-info process-attributes
+              ;; Emacs 30+ only.
+             file-user-uid))
     default-directory)
    ;; PROC.
    ((member operation '(file-notify-rm-watch file-notify-valid-p))
@@ -3714,6 +3716,15 @@ Let-bind it when necessary.")
         vec (concat "~" (substring filename (match-beginning 1))))
       (tramp-make-tramp-file-name (tramp-dissect-file-name filename)))))
 
+(defun tramp-handle-file-user-uid ()
+  "Like `user-uid' for Tramp files."
+  (let ((v (tramp-dissect-file-name default-directory)))
+    (or (tramp-get-remote-uid v 'integer)
+        ;; Some handlers for `tramp-get-remote-uid' return nil if they
+        ;; can't get the UID; always return -1 in this case for
+        ;; consistency.
+        -1)))
+
 (defun tramp-handle-access-file (filename string)
   "Like `access-file' for Tramp files."
   (setq filename (file-truename filename))
diff --git a/lisp/progmodes/cc-engine.el b/lisp/progmodes/cc-engine.el
index 8ac3ef6808..45d90ea243 100644
--- a/lisp/progmodes/cc-engine.el
+++ b/lisp/progmodes/cc-engine.el
@@ -10863,7 +10863,13 @@ This function might do hidden buffer changes."
                      ;; types; other identifiers could just as well be
                      ;; constants in C++.
                      (memq at-type '(known found)))))
-                  (throw 'at-decl-or-cast t)
+                  (progn
+                    ;; The user may be part way through typing a statement
+                    ;; beginning with an identifier.  This makes a 'maybe
+                    ;; type in the following "declarator"'s arglist suspect.
+                    (when (eq at-type 'maybe)
+                      (setq unsafe-maybe t))
+                    (throw 'at-decl-or-cast t))
                 ;; CASE 7
                 ;; Can't be a valid declaration or cast, but if we've found a
                 ;; specifier it can't be anything else either, so treat it as
diff --git a/lisp/progmodes/dockerfile-ts-mode.el 
b/lisp/progmodes/dockerfile-ts-mode.el
index 3f8766e671..1b91681f08 100644
--- a/lisp/progmodes/dockerfile-ts-mode.el
+++ b/lisp/progmodes/dockerfile-ts-mode.el
@@ -161,6 +161,10 @@ the subtrees."
     (setq-local treesit-simple-indent-rules
                 dockerfile-ts-mode--indent-rules)
 
+    ;; Navigation
+    (setq-local treesit-sentence-type-regexp
+                "instruction")
+
     ;; Font-lock.
     (setq-local treesit-font-lock-settings
                 dockerfile-ts-mode--font-lock-settings)
diff --git a/lisp/progmodes/eglot.el b/lisp/progmodes/eglot.el
index a846baa1b1..8ce1a8b7ba 100644
--- a/lisp/progmodes/eglot.el
+++ b/lisp/progmodes/eglot.el
@@ -1075,7 +1075,7 @@ suitable root directory for a given LSP server's 
purposes."
 
 ;;;###autoload
 (defun eglot (managed-major-mode project class contact language-id
-                                 &optional interactive)
+                                 &optional _interactive)
   "Start LSP server in support of PROJECT's buffers under MANAGED-MAJOR-MODE.
 
 This starts a Language Server Protocol (LSP) server suitable for the
@@ -1112,17 +1112,17 @@ described in `eglot-server-programs', which see.
 LANGUAGE-ID is the language ID string to send to the server for
 MANAGED-MAJOR-MODE, which matters to a minority of servers.
 
-INTERACTIVE is t if called interactively."
-  (interactive (append (eglot--guess-contact t) '(t)))
-  (setq managed-major-mode (eglot--ensure-list managed-major-mode))
-  (let* ((current-server (eglot-current-server))
-         (live-p (and current-server (jsonrpc-running-p current-server))))
-    (if (and live-p
-             interactive
-             (y-or-n-p "[eglot] Live process found, reconnect instead? "))
-        (eglot-reconnect current-server interactive)
-      (when live-p (ignore-errors (eglot-shutdown current-server)))
-      (eglot--connect managed-major-mode project class contact language-id))))
+INTERACTIVE is ignored and provided for backward compatibility."
+  (interactive
+   (let ((current-server (eglot-current-server)))
+     (unless (or (null current-server)
+                 (y-or-n-p "\
+[eglot] Shut down current connection before attempting new one?"))
+       (user-error "[eglot] Connection attempt aborted by user."))
+     (prog1 (append (eglot--guess-contact t) '(t))
+       (when current-server (ignore-errors (eglot-shutdown current-server))))))
+  (eglot--connect (eglot--ensure-list managed-major-mode)
+                  project class contact language-id))
 
 (defun eglot-reconnect (server &optional interactive)
   "Reconnect to SERVER.
diff --git a/lisp/progmodes/js.el b/lisp/progmodes/js.el
index fa3b4687ef..28305a0b39 100644
--- a/lisp/progmodes/js.el
+++ b/lisp/progmodes/js.el
@@ -3454,13 +3454,16 @@ This function is intended for use in 
`after-change-functions'."
        ((parent-is "statement_block") parent-bol js-indent-level)
 
        ;; JSX
-       ((node-is "jsx_fragment") parent typescript-ts-mode-indent-offset)
-       ((node-is "jsx_element") parent typescript-ts-mode-indent-offset)
-       ((node-is "jsx_expression") parent typescript-ts-mode-indent-offset)
-       ((node-is "jsx_self_closing_element") parent 
typescript-ts-mode-indent-offset)
+       ((match "<" "jsx_fragment") parent 0)
+       ((parent-is "jsx_fragment") parent js-indent-level)
        ((node-is "jsx_closing_element") parent 0)
-       ((node-is "/") parent 0)
-       ((node-is ">") parent 0)))))
+       ((node-is "jsx_element") parent js-indent-level)
+       ((parent-is "jsx_element") parent js-indent-level)
+       ((parent-is "jsx_opening_element") parent js-indent-level)
+       ((parent-is "jsx_expression") parent-bol js-indent-level)
+       ((match "/" "jsx_self_closing_element") parent 0)
+       ((parent-is "jsx_self_closing_element") parent js-indent-level)
+       (no-node parent-bol 0)))))
 
 (defvar js--treesit-keywords
   '("as" "async" "await" "break" "case" "catch" "class" "const" "continue"
diff --git a/lisp/progmodes/json-ts-mode.el b/lisp/progmodes/json-ts-mode.el
index fbcda22acc..f6a303290a 100644
--- a/lisp/progmodes/json-ts-mode.el
+++ b/lisp/progmodes/json-ts-mode.el
@@ -147,6 +147,8 @@ Return nil if there is no name or if NODE is not a defun 
node."
               (rx (or "pair" "object")))
   (setq-local treesit-defun-name-function #'json-ts-mode--defun-name)
 
+  (setq-local treesit-sentence-type-regexp "pair")
+
   ;; Font-lock.
   (setq-local treesit-font-lock-settings json-ts-mode--font-lock-settings)
   (setq-local treesit-font-lock-feature-list
diff --git a/lisp/progmodes/ruby-ts-mode.el b/lisp/progmodes/ruby-ts-mode.el
index d68b57966b..939c054b04 100644
--- a/lisp/progmodes/ruby-ts-mode.el
+++ b/lisp/progmodes/ruby-ts-mode.el
@@ -780,12 +780,20 @@ i.e. expr of def foo(args) = expr is returned."
            ;; but with node set to the statement and parent set to
            ;; body_statement for all others. ... Fine.  Be that way.
            ;; Ditto for "block" and "block_body"
-           ((node-is "body_statement") parent-bol ruby-indent-level)
-           ((parent-is "body_statement") (ruby-ts--bol 
ruby-ts--grand-parent-node) ruby-indent-level)
-           ((match "end" "do_block") parent-bol 0)
-           ((n-p-gp "block_body" "block" nil) parent-bol ruby-indent-level)
-           ((n-p-gp nil "block_body" "block") (ruby-ts--bol 
ruby-ts--grand-parent-node) ruby-indent-level)
-           ((match "}" "block") parent-bol 0)
+           ((node-is "body_statement")
+            (ruby-ts--block-indent-anchor ruby-ts--parent-node)
+            ruby-indent-level)
+           ((parent-is "body_statement")
+            (ruby-ts--block-indent-anchor ruby-ts--grand-parent-node)
+            ruby-indent-level)
+           ((match "end" "do_block") (ruby-ts--block-indent-anchor 
ruby-ts--parent-node) 0)
+           ((n-p-gp "block_body" "block" nil)
+            (ruby-ts--block-indent-anchor ruby-ts--parent-node)
+            ruby-indent-level)
+           ((n-p-gp nil "block_body" "block")
+            (ruby-ts--block-indent-anchor ruby-ts--grand-parent-node)
+            ruby-indent-level)
+           ((match "}" "block") (ruby-ts--block-indent-anchor 
ruby-ts--parent-node) 0)
 
            ;; Chained strings
            ((match "string" "chained_string") first-sibling 0)
@@ -794,6 +802,18 @@ i.e. expr of def foo(args) = expr is returned."
            (catch-all parent-bol ruby-indent-level))))
     `((ruby . ,common))))
 
+(defun ruby-ts--block-indent-anchor (block-node-getter)
+  (lambda (node parent _bol &rest _rest)
+    (let ((block-node (funcall block-node-getter node parent)))
+      (save-excursion
+        (goto-char
+         (treesit-node-start
+          (if ruby-block-indent
+              (ruby-ts--statement-ancestor block-node)
+            block-node)))
+        (back-to-indentation)
+        (point)))))
+
 (defun ruby-ts--class-or-module-p (node)
   "Predicate if NODE is a class or module."
   (string-match-p ruby-ts--class-or-module-regex (treesit-node-type node)))
diff --git a/lisp/progmodes/typescript-ts-mode.el 
b/lisp/progmodes/typescript-ts-mode.el
index cd631d048e..f7bf7ed7e4 100644
--- a/lisp/progmodes/typescript-ts-mode.el
+++ b/lisp/progmodes/typescript-ts-mode.el
@@ -97,13 +97,15 @@ Argument LANGUAGE is either `typescript' or `tsx'."
      ((parent-is "binary_expression") parent-bol 
typescript-ts-mode-indent-offset)
 
      ,@(when (eq language 'tsx)
-         `(((node-is "jsx_fragment") parent typescript-ts-mode-indent-offset)
-           ((node-is "jsx_element") parent typescript-ts-mode-indent-offset)
-           ((node-is "jsx_expression") parent typescript-ts-mode-indent-offset)
-           ((node-is "jsx_self_closing_element") parent 
typescript-ts-mode-indent-offset)
+         `(((match "<" "jsx_fragment") parent 0)
+           ((parent-is "jsx_fragment") parent typescript-ts-mode-indent-offset)
            ((node-is "jsx_closing_element") parent 0)
-           ((node-is "/") parent 0)
-           ((node-is ">") parent 0)))
+           ((node-is "jsx_element") parent typescript-ts-mode-indent-offset)
+           ((parent-is "jsx_element") parent typescript-ts-mode-indent-offset)
+           ((parent-is "jsx_opening_element") parent 
typescript-ts-mode-indent-offset)
+           ((parent-is "jsx_expression") parent-bol 
typescript-ts-mode-indent-offset)
+           ((match "/" "jsx_self_closing_element") parent 0)
+           ((parent-is "jsx_self_closing_element") parent 
typescript-ts-mode-indent-offset)))
      (no-node parent-bol 0))))
 
 (defvar typescript-ts-mode--keywords
diff --git a/lisp/simple.el b/lisp/simple.el
index 4b09f41de5..844cfa68b0 100644
--- a/lisp/simple.el
+++ b/lisp/simple.el
@@ -4730,6 +4730,18 @@ Also see the `async-shell-command-buffer' variable."
                      action))
       (user-error "Shell command in progress"))))
 
+(defun file-user-uid ()
+  "Return the connection-local effective uid.
+This is similar to `user-uid', but may invoke a file name handler
+based on `default-directory'.  See Info node `(elisp)Magic File
+Names'.
+
+If a file name handler is unable to retrieve the effective uid,
+this function will instead return -1."
+  (if-let ((handler (find-file-name-handler default-directory 'file-user-uid)))
+      (funcall handler 'file-user-uid)
+    (user-uid)))
+
 (defun max-mini-window-lines (&optional frame)
   "Compute maximum number of lines for echo area in FRAME.
 As defined by `max-mini-window-height'.  FRAME defaults to the
diff --git a/lisp/subr.el b/lisp/subr.el
index 1762c94a43..f909b63aab 100644
--- a/lisp/subr.el
+++ b/lisp/subr.el
@@ -2562,12 +2562,14 @@ The variable list SPEC is the same as in `if-let'."
 Evaluate each binding in turn, stopping if a binding value is nil.
 If all bindings are non-nil, eval BODY and repeat.
 
-The variable list SPEC is the same as in `if-let'."
+The variable list SPEC is the same as in `if-let*'."
   (declare (indent 1) (debug if-let))
   (let ((done (gensym "done")))
     `(catch ',done
        (while t
-         (if-let ,spec
+         ;; This is `if-let*', not `if-let', deliberately, despite the
+         ;; name of this macro.  See bug#60758.
+         (if-let* ,spec
              (progn
                ,@body)
            (throw ',done nil))))))
diff --git a/lisp/treesit.el b/lisp/treesit.el
index e9f5a8b37b..69bfff21df 100644
--- a/lisp/treesit.el
+++ b/lisp/treesit.el
@@ -1152,7 +1152,6 @@ See `treesit-simple-indent-presets'.")
                     (and (>= (point) comment-start-bol)
                          adaptive-fill-regexp
                          (looking-at adaptive-fill-regexp)
-                         (> (match-end 0) (match-beginning 0))
                          (match-end 0))))))
         ;; TODO: Document.
         (cons 'grand-parent
diff --git a/lisp/use-package/use-package-core.el 
b/lisp/use-package/use-package-core.el
index 379e119b60..7ab5bdc276 100644
--- a/lisp/use-package/use-package-core.el
+++ b/lisp/use-package/use-package-core.el
@@ -65,7 +65,7 @@
   :link '(custom-manual "(use-package) Top")
   :version "29.1")
 
-(defconst use-package-version "2.4.4"
+(defconst use-package-version "2.4.5"
   "This version of `use-package'.")
 
 (defcustom use-package-keywords
diff --git a/lisp/use-package/use-package.el b/lisp/use-package/use-package.el
index 7682468522..1b63a6d651 100644
--- a/lisp/use-package/use-package.el
+++ b/lisp/use-package/use-package.el
@@ -5,7 +5,7 @@
 ;; Author: John Wiegley <johnw@newartisans.com>
 ;; Maintainer: John Wiegley <johnw@newartisans.com>
 ;; Created: 17 Jun 2012
-;; Version: 2.4.4
+;; Version: 2.4.5
 ;; Package-Requires: ((emacs "24.3") (bind-key "2.4"))
 ;; Keywords: dotemacs startup speed config package extensions
 ;; URL: https://github.com/jwiegley/use-package
diff --git a/src/w32fns.c b/src/w32fns.c
index 192d3ddf27..b4192a5ffa 100644
--- a/src/w32fns.c
+++ b/src/w32fns.c
@@ -10396,8 +10396,8 @@ to be converted to forward slashes by the caller.  */)
 #endif /* WINDOWSNT */
 
 /* Query a value from the Windows Registry (under HKCU and HKLM),
-   where `key` is the registry key, `name` is the name, and `lpdwtype`
-   is a pointer to the return value's type. `lpwdtype` can be NULL if
+   where `key' is the registry key, `name' is the name, and `lpdwtype'
+   is a pointer to the return value's type. `lpwdtype' can be NULL if
    you do not care about the type.
 
    Returns: pointer to the value, or null pointer if the key/name does
@@ -10664,7 +10664,7 @@ pops up the Windows Run dialog, <lwindow>-<Pause> pops 
up the "System
 Properties" dialog, etc.  On Windows 10, no \"Windows\" key
 combinations are normally handed to applications.  To enable Emacs to
 process \"Windows\" key combinations, use the function
-`w32-register-hot-key`.
+`w32-register-hot-key'.
 
 For Windows 98/ME, see the doc string of `w32-phantom-key-code'.  */);
   Vw32_pass_lwindow_to_system = Qt;
@@ -10683,7 +10683,7 @@ pops up the Windows Run dialog, <rwindow>-<Pause> pops 
up the "System
 Properties" dialog, etc.  On Windows 10, no \"Windows\" key
 combinations are normally handed to applications.  To enable Emacs to
 process \"Windows\" key combinations, use the function
-`w32-register-hot-key`.
+`w32-register-hot-key'.
 
 For Windows 98/ME, see the doc string of `w32-phantom-key-code'.  */);
   Vw32_pass_rwindow_to_system = Qt;
@@ -10698,7 +10698,7 @@ acting on \"Windows\" key events when 
`w32-pass-lwindow-to-system' or
 `w32-pass-rwindow-to-system' is nil.
 
 This variable is only used on Windows 98 and ME.  For other Windows
-versions, see the documentation of the `w32-register-hot-key`
+versions, see the documentation of the `w32-register-hot-key'
 function.  */);
   /* Although 255 is technically not a valid key code, it works and
      means that this hack won't interfere with any real key code.  */
@@ -10732,7 +10732,7 @@ The value can be hyper, super, meta, alt, control or 
shift for the
 respective modifier, or nil to appear as the `lwindow' key.
 Any other value will cause the key to be ignored.
 
-Also see the documentation of the `w32-register-hot-key` function.  */);
+Also see the documentation of the `w32-register-hot-key' function.  */);
   Vw32_lwindow_modifier = Qnil;
 
   DEFVAR_LISP ("w32-rwindow-modifier",
@@ -10742,7 +10742,7 @@ The value can be hyper, super, meta, alt, control or 
shift for the
 respective modifier, or nil to appear as the `rwindow' key.
 Any other value will cause the key to be ignored.
 
-Also see the documentation of the `w32-register-hot-key` function.  */);
+Also see the documentation of the `w32-register-hot-key' function.  */);
   Vw32_rwindow_modifier = Qnil;
 
   DEFVAR_LISP ("w32-apps-modifier",
@@ -11271,7 +11271,7 @@ globals_of_w32fns (void)
     get_proc_addr (hm_kernel32, "SetThreadDescription");
 
   /* Support OS dark mode on Windows 10 version 1809 and higher.
-     See `w32_applytheme` which uses appropriate APIs per version of Windows.
+     See `w32_applytheme' which uses appropriate APIs per version of Windows.
      For future wretches who may need to understand Windows build numbers:
      
https://docs.microsoft.com/en-us/windows/release-health/release-information
   */
diff --git a/src/xterm.c b/src/xterm.c
index 028bb7582c..1373045393 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -5750,7 +5750,8 @@ xi_device_from_id (struct x_display_info *dpyinfo, int 
deviceid)
 
 static void
 xi_link_touch_point (struct xi_device_t *device,
-                    int detail, double x, double y)
+                    int detail, double x, double y,
+                    struct frame *frame)
 {
   struct xi_touch_point_t *touchpoint;
 
@@ -5759,6 +5760,7 @@ xi_link_touch_point (struct xi_device_t *device,
   touchpoint->x = x;
   touchpoint->y = y;
   touchpoint->number = detail;
+  touchpoint->frame = frame;
 
   device->touchpoints = touchpoint;
 }
@@ -5787,6 +5789,36 @@ xi_unlink_touch_point (int detail,
   return false;
 }
 
+/* Unlink all touch points associated with the frame F.
+   This is done upon unmapping or destroying F's window, because
+   touch point delivery after that point is undefined.  */
+
+static void
+xi_unlink_touch_points (struct frame *f)
+{
+  struct xi_device_t *device;
+  struct xi_touch_point_t **next, *last;
+  int i;
+
+  for (i = 0; i < FRAME_DISPLAY_INFO (f)->num_devices; ++i)
+    {
+      device = &FRAME_DISPLAY_INFO (f)->devices[i];
+
+      /* Now unlink all touch points on DEVICE matching F.  */
+
+      for (next = &device->touchpoints; (last = *next);)
+       {
+         if (last->frame == f)
+           {
+             *next = last->next;
+             xfree (last);
+           }
+         else
+           next = &last->next;
+       }
+    }
+}
+
 static struct xi_touch_point_t *
 xi_find_touch_point (struct xi_device_t *device, int detail)
 {
@@ -13535,6 +13567,10 @@ xi_disable_devices (struct x_display_info *dpyinfo,
 #ifdef HAVE_XINPUT2_2
   struct xi_touch_point_t *tem, *last;
 #endif
+#if defined HAVE_XINPUT2_2 && !defined HAVE_EXT_TOOL_BAR
+  struct x_output *output;
+  Lisp_Object tail, frame;
+#endif
 
   /* Don't pointlessly copy dpyinfo->devices if there are no devices
      to disable.  */
@@ -13577,6 +13613,34 @@ xi_disable_devices (struct x_display_info *dpyinfo,
                  tem = tem->next;
                  xfree (last);
                }
+
+#ifndef HAVE_EXT_TOOL_BAR
+
+             /* Now look through each frame on DPYINFO.  If it has an
+                outstanding tool bar press for this device, release
+                the tool bar.  */
+
+             FOR_EACH_FRAME (tail, frame)
+               {
+                 if (!FRAME_X_P (XFRAME (frame))
+                     || (FRAME_DISPLAY_INFO (XFRAME (frame))
+                         != dpyinfo))
+                   continue;
+
+                 output = FRAME_OUTPUT_DATA (XFRAME (frame));
+
+                 if (output->tool_bar_touch_device
+                     == dpyinfo->devices[i].device_id)
+                   {
+                     if (XFRAME (frame)->last_tool_bar_item != -1
+                         && WINDOWP (XFRAME (frame)->tool_bar_window))
+                       handle_tool_bar_click (XFRAME (frame), 0, 0,
+                                              false, 0);
+
+                     output->tool_bar_touch_device = 0;
+                   }
+               }
+#endif
 #endif
 
              goto out;
@@ -24209,6 +24273,73 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                }
 #endif
 
+#ifndef HAVE_EXT_TOOL_BAR
+             /* Is this a touch from a direct touch device that is in
+                the tool-bar?  */
+             if (device->direct_p
+                 && WINDOWP (f->tool_bar_window)
+                 && WINDOW_TOTAL_LINES (XWINDOW (f->tool_bar_window)))
+               {
+                 Lisp_Object window;
+                 int x = xev->event_x;
+                 int y = xev->event_y;
+
+                 window = window_from_coordinates (f, x, y, 0, true, true);
+                 /* Ignore button release events if the mouse
+                    wasn't previously pressed on the tool bar.
+                    We do this because otherwise selecting some
+                    text with the mouse and then releasing it on
+                    the tool bar doesn't stop selecting text,
+                    since the tool bar eats the button up
+                    event.  */
+                 tool_bar_p = EQ (window, f->tool_bar_window);
+
+                 /* If this touch has started in the tool bar, do not
+                    send it to Lisp.  Instead, simulate a tool bar
+                    click, releasing it once it goes away.  */
+
+                 if (tool_bar_p)
+                   {
+                     /* Call note_mouse_highlight on the tool bar
+                        item.  Otherwise, get_tool_bar_item will
+                        return 1.
+
+                        This is not necessary when mouse-highlight is
+                        nil.  */
+
+                     if (!NILP (Vmouse_highlight))
+                       {
+                         note_mouse_highlight (f, x, y);
+
+                         /* Always allow future mouse motion to
+                            update the mouse highlight, no matter
+                            where it is.  */
+                         memset (&dpyinfo->last_mouse_glyph, 0,
+                                 sizeof dpyinfo->last_mouse_glyph);
+                         dpyinfo->last_mouse_glyph_frame = f;
+                       }
+
+                     handle_tool_bar_click_with_device (f, x, y, true, 0,
+                                                        (source
+                                                         ? source->name : Qt));
+
+                     /* Flush any changes made by that to the front
+                        buffer.  */
+                     x_flush_dirty_back_buffer_on (f);
+
+                     /* Record the device and the touch ID on the
+                        frame.  That way, Emacs knows when to dismiss
+                        the tool bar click later.  */
+
+                     FRAME_OUTPUT_DATA (f)->tool_bar_touch_device
+                       = device->device_id;
+                     FRAME_OUTPUT_DATA (f)->tool_bar_touch_id = xev->detail;
+
+                     goto XI_OTHER;
+                   }
+               }
+#endif
+
              if (!menu_bar_p && !tool_bar_p)
                {
                  if (f && device->direct_p)
@@ -24218,13 +24349,16 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                      x_catch_errors (dpyinfo->display);
 
                      if (x_input_grab_touch_events)
-                       XIAllowTouchEvents (dpyinfo->display, xev->deviceid,
-                                           xev->detail, xev->event, 
XIAcceptTouch);
+                       XIAllowTouchEvents (dpyinfo->display,
+                                           xev->deviceid,
+                                           xev->detail, xev->event,
+                                           XIAcceptTouch);
 
                      if (!x_had_errors_p (dpyinfo->display))
                        {
-                         xi_link_touch_point (device, xev->detail, 
xev->event_x,
-                                              xev->event_y);
+                         xi_link_touch_point (device, xev->detail,
+                                              xev->event_x,
+                                              xev->event_y, f);
 
                          inev.ie.kind = TOUCHSCREEN_BEGIN_EVENT;
                          inev.ie.timestamp = xev->time;
@@ -24299,10 +24433,11 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                  for (touchpoint = device->touchpoints;
                       touchpoint; touchpoint = touchpoint->next)
                    {
-                     arg = Fcons (list3i (lrint (touchpoint->x),
-                                          lrint (touchpoint->y),
-                                          lrint (touchpoint->number)),
-                                  arg);
+                     if (touchpoint->frame == f)
+                       arg = Fcons (list3i (lrint (touchpoint->x),
+                                            lrint (touchpoint->y),
+                                            lrint (touchpoint->number)),
+                                    arg);
                    }
 
                  if (source)
@@ -24348,6 +24483,31 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                    }
                }
 
+             /* Now see if the touchpoint was previously on the tool bar.
+                If it was, release the tool bar.  */
+
+             if (!f)
+               f = x_window_to_frame (dpyinfo, xev->event);
+
+             if (f && (FRAME_OUTPUT_DATA (f)->tool_bar_touch_id
+                       == xev->detail))
+               {
+                 if (f->last_tool_bar_item != -1)
+                   handle_tool_bar_click_with_device (f, xev->event_x,
+                                                      xev->event_y,
+                                                      false, 0,
+                                                      (source
+                                                       ? source->name
+                                                       : Qnil));
+
+                 /* Cancel any outstanding mouse highlight.  */
+                 note_mouse_highlight (f, -1, -1);
+                 x_flush_dirty_back_buffer_on (f);
+
+                 /* Now clear the tool bar device.  */
+                 FRAME_OUTPUT_DATA (f)->tool_bar_touch_device = 0;
+               }
+
              goto XI_OTHER;
            }
 
@@ -28453,6 +28613,11 @@ x_make_frame_invisible (struct frame *f)
 
   block_input ();
 
+#ifdef HAVE_XINPUT2_2
+  /* Remove any touch points associated with F.  */
+  xi_unlink_touch_points (f);
+#endif
+
   /* Before unmapping the window, update the WM_SIZE_HINTS property to claim
      that the current position of the window is user-specified, rather than
      program-specified, so that when the window is mapped again, it will be
@@ -28658,6 +28823,11 @@ x_free_frame_resources (struct frame *f)
   xi_handle_delete_frame (dpyinfo, f);
 #endif
 
+#ifdef HAVE_XINPUT2_2
+  /* Remove any touch points associated with F.  */
+  xi_unlink_touch_points (f);
+#endif
+
   /* If a display connection is dead, don't try sending more
      commands to the X server.  */
   if (dpyinfo->display)
diff --git a/src/xterm.h b/src/xterm.h
index d768ba7ff8..28ae00ca19 100644
--- a/src/xterm.h
+++ b/src/xterm.h
@@ -257,10 +257,17 @@ struct xi_scroll_valuator_t
 
 struct xi_touch_point_t
 {
+  /* The next touch point in this list.  */
   struct xi_touch_point_t *next;
 
+  /* The touchpoint detail.  */
   int number;
+
+  /* The last known X and Y position of the touchpoint.  */
   double x, y;
+
+  /* The frame associated with this touch point.  */
+  struct frame *frame;
 };
 
 #endif
@@ -1295,6 +1302,16 @@ struct x_output
      VisibilityFullyObscured, but is set to something else in
      handle_one_xevent.  */
   int visibility_state;
+
+#ifdef HAVE_XINPUT2_2
+  /* The touch ID of the last touch point to have touched the tool
+     bar.  */
+  int tool_bar_touch_id;
+
+  /* The device that last touched the tool bar.  0 if no device
+     touched the tool bar.  */
+  int tool_bar_touch_device;
+#endif
 };
 
 enum
diff --git a/test/lisp/eshell/esh-var-tests.el 
b/test/lisp/eshell/esh-var-tests.el
index 3f602798db..0cc1b92266 100644
--- a/test/lisp/eshell/esh-var-tests.el
+++ b/test/lisp/eshell/esh-var-tests.el
@@ -746,6 +746,10 @@ it, since the setter is nil."
       (format "cd %s" ert-remote-temporary-file-directory))
      (eshell-match-command-output "echo $PATH" (regexp-quote remote-path)))))
 
+(ert-deftest esh-var-test/uid-var ()
+  "Test that $UID is equivalent to (user-uid) for local directories."
+  (eshell-command-result-equal "echo $UID" (user-uid)))
+
 (ert-deftest esh-var-test/last-status-var-lisp-command ()
   "Test using the \"last exit status\" ($?) variable with a Lisp command"
   (with-temp-eshell
diff --git a/test/lisp/progmodes/c-ts-mode-resources/indent.erts 
b/test/lisp/progmodes/c-ts-mode-resources/indent.erts
index 71524e273f..70fce68b0e 100644
--- a/test/lisp/progmodes/c-ts-mode-resources/indent.erts
+++ b/test/lisp/progmodes/c-ts-mode-resources/indent.erts
@@ -133,6 +133,20 @@ Name: Multiline Block Comments 4 (bug#60270)
  */
 =-=-=
 
+Name: Multiline Block Comments 5 (bug#60270)
+
+=-=
+/*
+line one
+line 2
+ */
+=-=
+/*
+  line one
+  line 2
+ */
+=-=-=
+
 
 Code:
   (lambda ()
diff --git a/test/lisp/progmodes/java-ts-mode-resources/indent.erts 
b/test/lisp/progmodes/java-ts-mode-resources/indent.erts
new file mode 100644
index 0000000000..e59d5fed8e
--- /dev/null
+++ b/test/lisp/progmodes/java-ts-mode-resources/indent.erts
@@ -0,0 +1,44 @@
+Code:
+  (lambda ()
+    (setq indent-tabs-mode nil)
+    (setq java-ts-mode-indent-offset 2)
+    (java-ts-mode)
+    (indent-region (point-min) (point-max)))
+
+Point-Char: |
+
+Name: Basic
+
+=-=
+public class Basic {
+  public void basic() {
+    return;
+  }
+}
+=-=-=
+
+Name: Empty Line
+
+=-=
+public class EmptyLine {
+  public void emptyLine() {
+    |
+  }
+}
+=-=-=
+
+Name: Statements
+
+=-=
+if (x) {
+  for (var foo : foos) {
+    |
+  }
+} else if (y) {
+  for (int i = 0; x < foos.size(); i++) {
+    return;
+  }
+} else {
+  return;
+}
+=-=-=
diff --git a/test/lisp/progmodes/java-ts-mode-resources/movement.erts 
b/test/lisp/progmodes/java-ts-mode-resources/movement.erts
new file mode 100644
index 0000000000..23639b1f5f
--- /dev/null
+++ b/test/lisp/progmodes/java-ts-mode-resources/movement.erts
@@ -0,0 +1,154 @@
+Code:
+  (lambda ()
+    (java-ts-mode)
+    (forward-sentence 1))
+
+Point-Char: |
+
+Name: forward-sentence moves over if
+
+=-=
+public class Basic {
+  public void basic() {
+    |if (x) {
+
+    }
+    log.info("some text: {}", text);
+    return;
+  }
+}
+=-=
+public class Basic {
+  public void basic() {
+    if (x) {
+
+    }|
+    log.info("some text: {}", text);
+    return;
+  }
+}
+=-=-=
+
+Name: forward-sentence moves over method invocation
+
+=-=
+public class Basic {
+  public void basic() {
+    |log.info("some text: {}", text);
+  }
+}
+=-=
+public class Basic {
+  public void basic() {
+    log.info("some text: {}", text);|
+  }
+}
+=-=-=
+
+Code:
+  (lambda ()
+    (java-ts-mode)
+    (forward-sentence 2))
+
+Name: forward-sentence moves over multiple statements
+
+=-=
+public class Basic {
+  public void basic() {
+    |return;
+    return;
+  }
+}
+=-=
+public class Basic {
+  public void basic() {
+    return;
+    return;|
+  }
+}
+=-=-=
+
+Code:
+  (lambda ()
+    (java-ts-mode)
+    (backward-sentence 1))
+
+Name: backward-sentence moves over one statement
+
+=-=
+public class Basic {
+  public void basic() {
+    return;|
+  }
+}
+=-=
+public class Basic {
+  public void basic() {
+    |return;
+  }
+}
+=-=-=
+
+Code:
+  (lambda ()
+    (java-ts-mode)
+    (beginning-of-defun))
+
+Name: beginning-of-defun moves to defun start
+
+=-=
+public class Basic {
+  public void basic() {
+    return;|
+  }
+}
+=-=
+public class Basic {
+|  public void basic() {
+    return;
+  }
+}
+=-=-=
+
+Code:
+  (lambda ()
+    (java-ts-mode)
+    (beginning-of-defun)
+    (beginning-of-defun))
+
+Name: beginning-of-defun moves to class
+
+=-=
+public class Basic {
+  public void basic() {
+    return;|
+  }
+}
+=-=
+|public class Basic {
+  public void basic() {
+    return;
+  }
+}
+=-=-=
+
+Code:
+  (lambda ()
+    (java-ts-mode)
+    (end-of-defun))
+
+Name: end-of-defun moves to defun end
+
+=-=
+public class Basic {
+  public void basic() {
+    return;|
+  }
+}
+=-=
+public class Basic {
+  public void basic() {
+    return;
+  }
+|}
+=-=-=
diff --git a/test/lisp/progmodes/java-ts-mode-tests.el 
b/test/lisp/progmodes/java-ts-mode-tests.el
new file mode 100644
index 0000000000..4fd8fc3019
--- /dev/null
+++ b/test/lisp/progmodes/java-ts-mode-tests.el
@@ -0,0 +1,35 @@
+;;; java-ts-mode-tests.el --- Tests for Tree-sitter-based Java 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 java-ts-mode-test-indentation ()
+  (skip-unless (treesit-ready-p 'java))
+  (ert-test-erts-file (ert-resource-file "indent.erts")))
+
+(ert-deftest java-ts-mode-test-movement ()
+  (skip-unless (treesit-ready-p 'java))
+  (ert-test-erts-file (ert-resource-file "movement.erts")))
+
+(provide 'java-ts-mode-tests)
+;;; java-ts-mode-tests.el ends here
diff --git a/test/lisp/progmodes/ruby-ts-mode-tests.el 
b/test/lisp/progmodes/ruby-ts-mode-tests.el
index b2c990f8e5..eaf6367a30 100644
--- a/test/lisp/progmodes/ruby-ts-mode-tests.el
+++ b/test/lisp/progmodes/ruby-ts-mode-tests.el
@@ -251,6 +251,7 @@ The whitespace before and including \"|\" on each line is 
removed."
          (kill-buffer buf)))))
 
 (ruby-ts-deftest-indent "ruby-method-params-indent.rb")
+(ruby-ts-deftest-indent "ruby-block-indent.rb")
 
 (provide 'ruby-ts-mode-tests)
 
diff --git a/test/lisp/progmodes/typescript-ts-mode-resources/indent.erts 
b/test/lisp/progmodes/typescript-ts-mode-resources/indent.erts
new file mode 100644
index 0000000000..146ee76574
--- /dev/null
+++ b/test/lisp/progmodes/typescript-ts-mode-resources/indent.erts
@@ -0,0 +1,73 @@
+Code:
+  (lambda ()
+    (setq indent-tabs-mode nil)
+    (setq typescript-ts-mode-indent-offset 2)
+    (typescript-ts-mode)
+    (indent-region (point-min) (point-max)))
+
+Point-Char: |
+
+Name: Basic indentation
+
+=-=
+const foo = () => {
+  console.log("bar");
+  if (x) {
+    return y;
+  } else if (y) {
+    return u;
+  }
+  return baz.x()
+    ? true
+    : false;
+}
+=-=-=
+
+Code:
+  (lambda ()
+    (setq indent-tabs-mode nil)
+    (setq tsx-ts-mode-indent-offset 2)
+    (tsx-ts-mode)
+    (indent-region (point-min) (point-max)))
+
+Name: JSX indentation
+
+=-=
+const foo = (props) => {
+  return (
+    <div>
+      <div>
+        <div>
+          <div>
+            {
+              props.foo
+                ? Hello, foo!
+                : Hello, World!;
+            }
+          </div>
+        </div>
+      </div>
+    </div>
+  );
+}
+=-=-=
+
+Name: JSX indentation with attributes
+
+=-=
+const foo = (props) => {
+  return (
+    <div
+      className={foo}
+      onClick={() => {
+        alert('???');
+        return () => {
+          return 5+5;
+        };
+      }}
+    >
+      <p>Some text</p>
+    </div>
+  );
+}
+=-=-=
diff --git a/test/lisp/progmodes/typescript-ts-mode-tests.el 
b/test/lisp/progmodes/typescript-ts-mode-tests.el
new file mode 100644
index 0000000000..126f5e3298
--- /dev/null
+++ b/test/lisp/progmodes/typescript-ts-mode-tests.el
@@ -0,0 +1,31 @@
+;;; typescript-ts-mode-tests.el --- Tests for Tree-sitter-based TypeScript 
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 typescript-ts-mode-test-indentation ()
+  (skip-unless (treesit-ready-p 'typescript))
+  (ert-test-erts-file (ert-resource-file "indent.erts")))
+
+(provide 'typescript-ts-mode-tests)
+;;; typescript-ts-mode-tests.el ends here



reply via email to

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