From c8d548097278683c94eced742a1a1bea387ced2d Mon Sep 17 00:00:00 2001 From: Stefan Kangas Date: Sun, 15 Jan 2023 14:30:46 +0100 Subject: [PATCH 01/21] Bump use-package version for Emacs 29.1 * lisp/use-package/use-package.el: Bump version to 2.4.5. --- lisp/use-package/use-package-core.el | 2 +- lisp/use-package/use-package.el | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lisp/use-package/use-package-core.el b/lisp/use-package/use-package-core.el index 379e119b60f..7ab5bdc276f 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 7682468522d..1b63a6d651a 100644 --- a/lisp/use-package/use-package.el +++ b/lisp/use-package/use-package.el @@ -5,7 +5,7 @@ ;; Author: John Wiegley ;; Maintainer: John Wiegley ;; 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 From f16bd1ead430294ff90cb4c3f0aba608a719a2e7 Mon Sep 17 00:00:00 2001 From: Sean Whitton Date: Sun, 15 Jan 2023 09:57:41 -0700 Subject: [PATCH 02/21] Revert "* lisp/subr.el (while-let): Use if-let, not if-let* (bug#60758)." This reverts commit 083badc9c122a802080552e7771e78ee47c01e3c. --- lisp/subr.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lisp/subr.el b/lisp/subr.el index ab451b5613b..34dd847e9d5 100644 --- a/lisp/subr.el +++ b/lisp/subr.el @@ -2545,7 +2545,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)))))) From 82ae9caaddb561de7709dbab818311a6e3db3f50 Mon Sep 17 00:00:00 2001 From: Sean Whitton Date: Sun, 15 Jan 2023 10:01:41 -0700 Subject: [PATCH 03/21] * lisp/subr.el (while-let): Fix docs if-let->if-let* (bug#60758). --- lisp/subr.el | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lisp/subr.el b/lisp/subr.el index 34dd847e9d5..0f754fcd31f 100644 --- a/lisp/subr.el +++ b/lisp/subr.el @@ -2540,11 +2540,13 @@ 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 + ;; This is `if-let*', not `if-let', deliberately, despite the + ;; name of this macro. See bug#60758. (if-let* ,spec (progn ,@body) From 44c9cb8653d19843b5e9f131b139aad7c1c4774b Mon Sep 17 00:00:00 2001 From: Theodor Thornhill Date: Sun, 15 Jan 2023 21:31:16 +0100 Subject: [PATCH 04/21] Improve indentation for jsx * lisp/progmodes/js.el (js--treesit-indent-rules): Use more parent anchors and fix typo with wrong indent offset variable. * lisp/progmodes/typescript-ts-mode.el (typescript-ts-mode--indent-rules): Use more parent anchors. --- lisp/progmodes/js.el | 15 +++++++++------ lisp/progmodes/typescript-ts-mode.el | 14 ++++++++------ 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/lisp/progmodes/js.el b/lisp/progmodes/js.el index 058c8907bb5..cc556c4d0ec 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/typescript-ts-mode.el b/lisp/progmodes/typescript-ts-mode.el index 037d5c8e87e..ffd5b941daf 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 From 352e41016bcaab8566347091b6b61908a9b57b57 Mon Sep 17 00:00:00 2001 From: Dmitry Gutov Date: Mon, 16 Jan 2023 05:17:05 +0200 Subject: [PATCH 05/21] ruby-ts-mode: Support the option ruby-block-indent * lisp/progmodes/ruby-ts-mode.el (ruby-ts--block-indent-anchor): New function. (ruby-ts--indent-rules): Use it. * test/lisp/progmodes/ruby-ts-mode-tests.el: Run indent test for ruby-block-indent.rb. --- lisp/progmodes/ruby-ts-mode.el | 32 ++++++++++++++++++----- test/lisp/progmodes/ruby-ts-mode-tests.el | 1 + 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/lisp/progmodes/ruby-ts-mode.el b/lisp/progmodes/ruby-ts-mode.el index d68b57966ba..939c054b041 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/test/lisp/progmodes/ruby-ts-mode-tests.el b/test/lisp/progmodes/ruby-ts-mode-tests.el index b2c990f8e56..eaf6367a306 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) From 3d1e74c82a84d9b2c5ad45a377512b5ee83b8d47 Mon Sep 17 00:00:00 2001 From: Yuan Fu Date: Mon, 16 Jan 2023 00:23:47 -0800 Subject: [PATCH 06/21] Fix tree-sitter indent preset function (bug#60270) * lisp/treesit.el (treesit-simple-indent-presets): Fix prev-adaptive-prefix so it doesn't return nil if the previous line has no prefix. * test/lisp/progmodes/c-ts-mode-resources/indent.erts: New test. --- lisp/treesit.el | 1 - .../lisp/progmodes/c-ts-mode-resources/indent.erts | 14 ++++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/lisp/treesit.el b/lisp/treesit.el index ffc78b93032..5e6f109531e 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/test/lisp/progmodes/c-ts-mode-resources/indent.erts b/test/lisp/progmodes/c-ts-mode-resources/indent.erts index 71524e273f3..70fce68b0ec 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 () From 67df34c143d1adbf6d2817abb5da5dcad06369bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20T=C3=A1vora?= Date: Mon, 16 Jan 2023 11:48:09 +0000 Subject: [PATCH 07/21] Fix M-x eglot prompt when connection already exists (bug#60557) Before this change, if a current connection existed at the time of M-x eglot, user would be first asked to enter into M-x eglot's interactive spec details about new command line arguments, and only afterwards be prompted about what to do with the current connection (which could be to reconnect to it using the same arguments, or tear it down and make a new one). This is very confusing, as users may not be fully aware of the distinction between "reconnect" vs "disconnect-and-connect". They might not know if any new command line arguments provided are taking effect or not. This change simplifies this and removes the option to "reconnect instead" from M-x eglot (users can do that at any time via M-x eglot-reconnect). It also ensures that users are informed about a current connection before asking to enter new command line arguments and not the other way round. * lisp/progmodes/eglot.el (eglot): Rework. --- lisp/progmodes/eglot.el | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/lisp/progmodes/eglot.el b/lisp/progmodes/eglot.el index 0082a171303..445d6ee9b5e 100644 --- a/lisp/progmodes/eglot.el +++ b/lisp/progmodes/eglot.el @@ -1113,16 +1113,16 @@ 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 + (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. From e84111a0017b953be363210a68ac0c05f3f864bb Mon Sep 17 00:00:00 2001 From: Theodor Thornhill Date: Mon, 16 Jan 2023 08:49:40 +0100 Subject: [PATCH 08/21] Add sentence-nodes to dockerfile-ts-mode * lisp/progmodes/dockerfile-ts-mode.el (dockerfile-ts-mode): Catch all instructions. --- lisp/progmodes/dockerfile-ts-mode.el | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lisp/progmodes/dockerfile-ts-mode.el b/lisp/progmodes/dockerfile-ts-mode.el index 3f8766e6713..1b91681f085 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) From c8dd37b16c574beda900d4ee48ac7b4ab4a2ee56 Mon Sep 17 00:00:00 2001 From: Theodor Thornhill Date: Mon, 16 Jan 2023 14:33:27 +0100 Subject: [PATCH 09/21] Add some basic tests for java-ts-mode and typescript-ts-mode * test/lisp/progmodes/java-ts-mode-resources/indent.erts: New file with tests for indentation. * test/lisp/progmodes/java-ts-mode-resources/movement.erts: New file with tests for movement. * test/lisp/progmodes/java-ts-mode-tests.el: New tests. * test/lisp/progmodes/typescript-ts-mode-resources/indent.erts: New file with tests for indentation. * test/lisp/progmodes/typescript-ts-mode-tests.el: New tests. --- .../java-ts-mode-resources/indent.erts | 44 +++++ .../java-ts-mode-resources/movement.erts | 154 ++++++++++++++++++ test/lisp/progmodes/java-ts-mode-tests.el | 35 ++++ .../typescript-ts-mode-resources/indent.erts | 73 +++++++++ .../progmodes/typescript-ts-mode-tests.el | 31 ++++ 5 files changed, 337 insertions(+) create mode 100644 test/lisp/progmodes/java-ts-mode-resources/indent.erts create mode 100644 test/lisp/progmodes/java-ts-mode-resources/movement.erts create mode 100644 test/lisp/progmodes/java-ts-mode-tests.el create mode 100644 test/lisp/progmodes/typescript-ts-mode-resources/indent.erts create mode 100644 test/lisp/progmodes/typescript-ts-mode-tests.el 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 00000000000..e59d5fed8e8 --- /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 00000000000..23639b1f5ff --- /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 00000000000..4fd8fc3019f --- /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 . + +;;; 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/typescript-ts-mode-resources/indent.erts b/test/lisp/progmodes/typescript-ts-mode-resources/indent.erts new file mode 100644 index 00000000000..146ee76574e --- /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 ( +
+
+
+
+ { + props.foo + ? Hello, foo! + : Hello, World!; + } +
+
+
+
+ ); +} +=-=-= + +Name: JSX indentation with attributes + +=-= +const foo = (props) => { + return ( +
{ + alert('???'); + return () => { + return 5+5; + }; + }} + > +

Some text

+
+ ); +} +=-=-= 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 00000000000..126f5e3298f --- /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 . + +;;; 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 From 77659bd46345b86159d8a5d4b6f4993ec20c30a6 Mon Sep 17 00:00:00 2001 From: Theodor Thornhill Date: Mon, 16 Jan 2023 14:48:56 +0100 Subject: [PATCH 10/21] Add sentence node regexp to json-ts-mode * lisp/progmodes/json-ts-mode.el (json-ts-mode): Add pair for sentence movement. --- lisp/progmodes/json-ts-mode.el | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lisp/progmodes/json-ts-mode.el b/lisp/progmodes/json-ts-mode.el index fbcda22acca..f6a303290a8 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 From 7c8eac8fbcb8cc8a4ededd86f4d2c7a507d8294c Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Mon, 16 Jan 2023 16:00:18 +0200 Subject: [PATCH 11/21] ; * src/w32fns.c: Fix quoting. Patch by Arash Esbati . --- src/w32fns.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/w32fns.c b/src/w32fns.c index 192d3ddf27a..71206b8874c 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 @@ -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 */ From 1b458aced723dc752a699e509816b92399087775 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Mon, 16 Jan 2023 16:08:46 +0200 Subject: [PATCH 12/21] ; * lisp/progmodes/eglot.el: Remove stray space. --- lisp/progmodes/eglot.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lisp/progmodes/eglot.el b/lisp/progmodes/eglot.el index 445d6ee9b5e..10512633181 100644 --- a/lisp/progmodes/eglot.el +++ b/lisp/progmodes/eglot.el @@ -1121,7 +1121,7 @@ INTERACTIVE is t if called interactively." (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) + (eglot--connect (eglot--ensure-list managed-major-mode) project class contact language-id)) (defun eglot-reconnect (server &optional interactive) From f367ba3ed03526356448a94addbb8554ece2f482 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Mon, 16 Jan 2023 16:52:48 +0200 Subject: [PATCH 13/21] ; Avoid byte-compiler warning in eglot.el * lisp/progmodes/eglot.el (eglot): Rename INTERACTIVE to avoid byte-compiler warning. Update the doc string. (Bug#60557) --- lisp/progmodes/eglot.el | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lisp/progmodes/eglot.el b/lisp/progmodes/eglot.el index 10512633181..dc73152f5ab 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,7 +1112,7 @@ 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 is ignored and provided for backward compatibility." (interactive (let ((current-server (eglot-current-server))) (unless (or (null current-server) From 140824dc099a84556341f089e8a939f4a80c3f7f Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Mon, 16 Jan 2023 16:55:01 +0200 Subject: [PATCH 14/21] ; Fix more quoting in w32fns.c. --- src/w32fns.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/w32fns.c b/src/w32fns.c index 71206b8874c..b4192a5ffa6 100644 --- a/src/w32fns.c +++ b/src/w32fns.c @@ -10664,7 +10664,7 @@ pops up the Windows Run dialog, - 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, - 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; From c1d32d9a20dc94d403725c288d168451b916c034 Mon Sep 17 00:00:00 2001 From: Alan Mackenzie Date: Mon, 16 Jan 2023 17:44:44 +0000 Subject: [PATCH 15/21] CC Mode: Prevent ids in temporary "declarators" getting into c-found-types This should fix bug #60765. In the scenario type an identifier in front of foo (bar, baz), as when started a new statement. This temporarily makes the function call a declarator, and bar and baz types. Don't enter bar and baz into c-found-types. * lisp/progmodes/cc-engine.el (c-forward-decl-or-cast-1) (CASE 6): When a 'maybe type triggers this case, set `unsafe-maybe' to non-nil. --- lisp/progmodes/cc-engine.el | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lisp/progmodes/cc-engine.el b/lisp/progmodes/cc-engine.el index 8ac3ef6808d..45d90ea2431 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 From e8c77d9abda9c5c48de546a4ff667ffdf3d27c94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mattias=20Engdeg=C3=A5rd?= Date: Sun, 15 Jan 2023 15:23:44 +0100 Subject: [PATCH 16/21] Fix hfy-exclude-file-rules (bug#60562) * lisp/htmlfontify.el (hfy-exclude-file-rules): Fix broken defcustom type; no longer fails test-custom-opts. Fix regexps not to use newline-sensitive patterns like `.` and `$` which do not make sense when matching file names. Better doc string. * lisp/htmlfontify.el (hfy-list-files): Simplify regexp argument. --- lisp/htmlfontify.el | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/lisp/htmlfontify.el b/lisp/htmlfontify.el index 0959405081f..1ab33cc6411 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 From 2a85d7a07c16dd854490b5eff72930d4a80b1415 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mattias=20Engdeg=C3=A5rd?= Date: Thu, 12 Jan 2023 14:07:45 +0100 Subject: [PATCH 17/21] Optimise `apply` with `cons` in tail argument * lisp/emacs-lisp/byte-opt.el (byte-optimize-apply): Transform (apply F ... (cons X Y)) -> (apply F ... X Y) This pattern is seen both in hand-written code and in backquote expansions. --- lisp/emacs-lisp/byte-opt.el | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lisp/emacs-lisp/byte-opt.el b/lisp/emacs-lisp/byte-opt.el index d7a0d851e01..039cebedb44 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))) From bcaa63ac506dc070b29db13326801ff978e8b00d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mattias=20Engdeg=C3=A5rd?= Date: Thu, 12 Jan 2023 15:38:15 +0100 Subject: [PATCH 18/21] * lisp/emacs-lisp/bytecomp.el (format-message): Warn on bad arity. --- lisp/emacs-lisp/bytecomp.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lisp/emacs-lisp/bytecomp.el b/lisp/emacs-lisp/bytecomp.el index 23d02ba92cf..fb4b73b1c14 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) From 0bb8a011d57cb55c16ff502125b60e8e3bb3d5aa Mon Sep 17 00:00:00 2001 From: Jim Porter Date: Tue, 10 Jan 2023 15:35:18 -0800 Subject: [PATCH 19/21] Add 'file-user-uid' to get the connection-local effective UID In particular, this lets Eshell show a "#" root prompt sigil when the user has sudo'ed via "cd /sudo::" (bug#60722). * lisp/simple.el (file-user-uid): New function. * lisp/net/tramp.el (tramp-file-name-for-operation): Add 'file-user-uid'. (tramp-handle-file-user-uid): New function. * lisp/net/tramp-adb.el (tramp-adb-file-name-handler-alist): * lisp/net/tramp-crypt.el (tramp-crypt-file-name-handler-alist): * lisp/net/tramp-gvfs.el (tramp-gvfs-file-name-handler-alist): * lisp/net/tramp-rclone.el (tramp-rclone-file-name-handler-alist): * lisp/net/tramp-sh.el (tramp-sh-file-name-handler-alist): * lisp/net/tramp-smb.el (tramp-smb-file-name-handler-alist): * lisp/net/tramp-sshfs.el (tramp-sshfs-file-name-handler-alist): * lisp/net/tramp-sudoedit.el (tramp-sudoedit-file-name-handler-alist): Add 'file-user-uid'. * lisp/net/tramp-archive.el (tramp-archive-handle-file-user-uid): New function... (tramp-archive-file-name-handler-alist): ... use it. * lisp/eshell/em-prompt.el (eshell-prompt-function): Use 'file-user-uid'. * lisp/eshell/esh-var.el (eshell-variable-aliases-list): Add '$UID'. * test/lisp/eshell/esh-var-tests.el (esh-var-test/uid-var): New test. * doc/lispref/os.texi (User Identification): Document 'file-user-uid'. * doc/lispref/files.texi (Magic File Names): Mention 'file-user-uid'. * doc/misc/eshell.texi (Variables): Document '$UID'. Add a missing index entry for '$INSIDE_EMACS'. * etc/NEWS: Announce 'file-user-uid'. --- doc/lispref/files.texi | 6 ++++-- doc/lispref/os.texi | 10 ++++++++++ doc/misc/eshell.texi | 8 ++++++++ etc/NEWS | 6 ++++++ lisp/eshell/em-prompt.el | 2 +- lisp/eshell/esh-var.el | 1 + 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/simple.el | 12 ++++++++++++ test/lisp/eshell/esh-var-tests.el | 4 ++++ 18 files changed, 73 insertions(+), 4 deletions(-) diff --git a/doc/lispref/files.texi b/doc/lispref/files.texi index 5cc4c1e7ddf..ad01e0f2886 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 3be7036f637..bca62a7a8de 100644 --- a/doc/lispref/os.texi +++ b/doc/lispref/os.texi @@ -1277,6 +1277,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 fc7d52eb711..c40ff58f42c 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 068f7a27db8..cde6783349f 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/eshell/em-prompt.el b/lisp/eshell/em-prompt.el index 52d46282c52..b3a0fadf618 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 811bb9957cf..fd76a2c6f09 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/net/tramp-adb.el b/lisp/net/tramp-adb.el index 29b9f894ec3..10f33e5f929 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 3b1d568c127..b9cf85bd843 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 507fd432419..b9d0d96eccc 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 ea774d0b9b7..02ceb2979f7 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 b28f9f64952..9eb2a54cdcf 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 acbb6aea135..46b1f612101 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 b3f0344f818..9d03490f1d5 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 27b2854e451..65c4bf23c38 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 ce080918e0f..db7ac842871 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 169cf1982b4..fab1962d2b7 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/simple.el b/lisp/simple.el index 4b09f41de55..844cfa68b08 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/test/lisp/eshell/esh-var-tests.el b/test/lisp/eshell/esh-var-tests.el index 3f602798dbe..0cc1b92266f 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 From b9025c507a3a7dae4de19b18cafaa09b18183832 Mon Sep 17 00:00:00 2001 From: Po Lu Date: Tue, 17 Jan 2023 18:28:37 +0800 Subject: [PATCH 20/21] Correctly handle touches on the tool bar * src/xterm.c (xi_link_touch_point): New argument `frame'. Set new field `touchpoint->frame' to it. (xi_unlink_touch_points): New function. (xi_disable_devices): Clear the tool bar device on frames whose tool bar device matches this field. (handle_one_xevent): If an XI_TouchBegin event lands on the tool bar, then simulate a pointer click. Ignore future events from that touchpoint from there onwards. (x_make_frame_invisible, x_free_frame_resources): Unlink touch points associated with the frame. * src/xterm.h (struct xi_touch_point_t): New field `frame'. (struct x_output): New fields for keeping track of tool bar touches. --- src/xterm.c | 155 +++++++++++++++++++++++++++++++++++++++++++++++++--- src/xterm.h | 17 ++++++ 2 files changed, 163 insertions(+), 9 deletions(-) diff --git a/src/xterm.c b/src/xterm.c index 028bb7582c4..6ae7e97f45a 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,48 @@ 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) + { + handle_tool_bar_click (f, x, y, true, 0); + + /* 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 +24324,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 +24408,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 +24458,23 @@ 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 (f, xev->event_x, xev->event_y, + false, 0); + + /* Now clear the tool bar device. */ + FRAME_OUTPUT_DATA (f)->tool_bar_touch_device = 0; + } + goto XI_OTHER; } @@ -28453,6 +28580,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 +28790,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 d768ba7ff8d..28ae00ca190 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 From 96015c9c8cc1720e8ee7cd9cea4de48126dd9122 Mon Sep 17 00:00:00 2001 From: Po Lu Date: Tue, 17 Jan 2023 18:54:22 +0800 Subject: [PATCH 21/21] Make tool bar highlight work correctly during touch events * src/xterm.c (handle_one_xevent): Before activating the tool bar in response to a touch event, set the mouse highlight to that location. After the touch ends, clear the mouse highlight. --- src/xterm.c | 39 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 36 insertions(+), 3 deletions(-) diff --git a/src/xterm.c b/src/xterm.c index 6ae7e97f45a..1373045393a 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -24300,7 +24300,32 @@ handle_one_xevent (struct x_display_info *dpyinfo, if (tool_bar_p) { - handle_tool_bar_click (f, x, y, true, 0); + /* 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 @@ -24468,8 +24493,16 @@ handle_one_xevent (struct x_display_info *dpyinfo, == xev->detail)) { if (f->last_tool_bar_item != -1) - handle_tool_bar_click (f, xev->event_x, xev->event_y, - false, 0); + 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;