diff --git a/configure.ac b/configure.ac index 1f5618a172f..bdcce8d8694 100644 --- a/configure.ac +++ b/configure.ac @@ -1581,12 +1581,12 @@ AS_IF([test $gl_gcc_warnings = no], # clang is unduly picky about some things. if test "$emacs_cv_clang" = yes; then + gl_WARN_ADD([-Wno-bitwise-instead-of-logical]) gl_WARN_ADD([-Wno-missing-braces]) gl_WARN_ADD([-Wno-null-pointer-arithmetic]) gl_WARN_ADD([-Wno-implicit-const-int-float-conversion]) gl_WARN_ADD([-Wno-int-in-bool-context]) gl_WARN_ADD([-Wno-shift-overflow]) - gl_WARN_ADD([-Wno-bitwise-instead-of-logical]) fi # This causes too much noise in the MinGW build diff --git a/doc/emacs/modes.texi b/doc/emacs/modes.texi index 06f9929092c..0e4b15fb514 100644 --- a/doc/emacs/modes.texi +++ b/doc/emacs/modes.texi @@ -429,8 +429,11 @@ For example, one element normally found in the list has the form @code{(@t{"\\.c\\'"} . c-mode)}, and it is responsible for selecting C mode for files whose names end in @file{.c}. (Note that @samp{\\} is needed in Lisp syntax to include a @samp{\} in the string, which must -be used to suppress the special meaning of @samp{.} in regexps.) If -the element has the form @w{@code{(@var{regexp} @var{mode-function} +be used to suppress the special meaning of @samp{.} in regexps.) + +@cindex backup files, choosing a major mode +@cindex encrypted files, choosing a major mode +If the element has the form @w{@code{(@var{regexp} @var{mode-function} @var{flag})}} and @var{flag} is non-@code{nil}, then after calling @var{mode-function} (if it is non-@code{nil}), Emacs discards the suffix that matched @var{regexp} and searches the list again for diff --git a/doc/lispref/positions.texi b/doc/lispref/positions.texi index 8d95ecee7ab..838877b6282 100644 --- a/doc/lispref/positions.texi +++ b/doc/lispref/positions.texi @@ -875,6 +875,23 @@ by using @code{forward-sentence} and @code{backward-sentence}(@pxref{Moving by Sentences,,, emacs, The extensible self-documenting text editor}). +@defvar treesit-sexp-type-regexp +The value of this variable is a regexp matching the node type of sexp +nodes. (For ``node'' and ``node type'', @pxref{Parsing Program +Source}.) +@end defvar + +@findex treesit-forward-sexp +@findex forward-sexp@r{, and tree-sitter} +@findex backward-sexp@r{, and tree-sitter} +If Emacs is compiled with tree-sitter, it can use the tree-sitter +parser information to move across syntax constructs. Since what +exactly is considered a sexp varies between languages, a major mode +should set @code{treesit-sexp-type-regexp} to determine that. Then +the mode can get navigation-by-sexp functionality for free, by using +@code{forward-sexp} and @code{backward-sexp}(@pxref{Moving by +Sentences,,, emacs, The extensible self-documenting text editor}). + @node Skipping Characters @subsection Skipping Characters @cindex skipping characters diff --git a/etc/NEWS b/etc/NEWS index a309cd17a93..678a5a70ca7 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -63,17 +63,21 @@ trash when deleting. Default is nil. Many touch screen gestures are now implemented, as is support for tapping buttons and opening menus. +** New command 'kill-matching-buffers-no-ask'. +Kills buffers whose name matches a regexp without asking for +confirmation. + ** New helper variable 'transpose-sexps-function'. Emacs now can set this variable to customize the behavior of the 'transpose-sexps' function. ** New function 'transpose-sexps-default-function'. The previous implementation is moved into its own function, to be -bound by transpose-sexps-function'. +bound by 'transpose-sexps-function'. ** New function 'treesit-transpose-sexps'. -treesit.el now unconditionally sets 'transpose-sexps-function' for all -Tree-sitter modes. This functionality utilizes the new +Tree-sitter now unconditionally sets 'transpose-sexps-function' for all +tree-sitter enabled modes. This functionality utilizes the new 'transpose-sexps-function'. ** Commands and variables to move by program statements @@ -86,13 +90,22 @@ Major modes can now set this variable to customize the behavior of the The previous implementation of 'forward-sentence' is moved into its own function, to be bound by 'forward-sentence-function'. -*** New defvar-local 'treesit-sentence-type-regexp. +*** New buffer-local variable 'treesit-sentence-type-regexp'. Similarly to 'treesit-defun-type-regexp', this variable is used to -define "sentences" in Tree-sitter enabled modes. +define "sentences" in tree-sitter enabled modes. *** New function 'treesit-forward-sentence'. -All tree-sitter modes that define 'treesit-sentence-type-regexp' now -set 'forward-sentence-function' to call 'treesit-forward-sentence'. +All tree-sitter enabled modes that define 'treesit-sentence-type-regexp' +now set 'forward-sentence-function' to call 'treesit-forward-sentence'. + +*** New buffer-local variable 'treesit-sexp-type-regexp'. +Similarly to 'treesit-defun-type-regexp', this variable is used to +define "sexps" in tree-sitter enabled modes. + +*** New function 'treesit-forward-sexp'. +Tree-sitter conditionally sets 'forward-sexp-function' for major modes +that have defined 'treesit-sexp-type-regexp' to enable sexp-related +motion commands. * Changes in Specialized Modes and Packages in Emacs 30.1 @@ -139,10 +152,10 @@ manual. --- *** Eshell now uses 'field' properties in its output. -In particular, this means that pressing the key moves the point -to the beginning of your input, not the beginning of the whole line. -If you want to go back to the old behavior, add something like this to -your configuration: +In particular, this means that pressing the '' key moves the +point to the beginning of your input, not the beginning of the whole +line. If you want to go back to the old behavior, add something like +this to your configuration: (keymap-set eshell-mode-map "" #'eshell-bol-ignoring-prompt) @@ -164,14 +177,14 @@ point is not in a comment or a string. It is by default bound to +++ *** New connection method "toolbox". -This allow accessing system containers provided by Toolbox. +This allows accessing system containers provided by Toolbox. ** EWW +++ *** 'eww-open-file' can now display the file in a new buffer. -By default, the command reuses the '*eww*' buffer, but if called with -the new argument non-nil, it will use a new buffer instead. +By default, the command reuses the "*eww*" buffer, but if called with +the new argument NEW-BUFFER non-nil, it will use a new buffer instead. Interactively, invoke 'eww-open-file' with a prefix argument to activate this behavior. diff --git a/etc/NEWS.29 b/etc/NEWS.29 index 9f735bec443..38f2db26a1a 100644 --- a/etc/NEWS.29 +++ b/etc/NEWS.29 @@ -53,29 +53,31 @@ yourself. Many libraries can be downloaded from the tree-sitter site: https://github.com/tree-sitter -To compile such a library, compile the files "scanner.c" and "parser.c" -(sometimes named "scanner.cc" and "parser.cc") in the "src" subdirectory -of the library's source tree using the C or C++ compiler, then link -these two files into a shared library named "libtree-sitter-LANG.so", -where LANG is the name of the language supported by the grammar as it -is expected by the Emacs major mode (for example, "c" for 'c-ts-mode', -"cpp" for 'c++-ts-mode', "python" for 'python-ts-mode', etc.). Then place -the shared library you've built in the same directory where you keep -the other shared libraries used by Emacs, or in the "tree-sitter" -subdirectory of your 'user-emacs-directory', or in a directory -mentioned in the variable 'treesit-extra-load-path'. - -You only need to install language grammar libraries required by the -Emacs modes you will use, as Emacs loads these libraries only when the -corresponding mode is turned on in some buffer for the first time in -an Emacs session. - Emacs provides a user command, 'treesit-install-language-grammar', that automates the download and build process of a grammar library. It prompts for the language, the URL of the language grammar's VCS repository, and then uses the installed C/C++ compiler to build the library and install it. +You can also do this manually. To compile such a library after +cloning its Git repository, compile the files "scanner.c" and +"parser.c" (sometimes named "scanner.cc" and "parser.cc") in the "src" +subdirectory of the library's source tree using the C or C++ compiler, +then link these two files into a shared library named +"libtree-sitter-LANG.so", where LANG is the name of the language +supported by the grammar as it is expected by the Emacs major mode +(for example, "c" for 'c-ts-mode', "cpp" for 'c++-ts-mode', "python" +for 'python-ts-mode', etc.). Then place the shared library you've +built in the same directory where you keep the other shared libraries +used by Emacs, or in the "tree-sitter" subdirectory of your +'user-emacs-directory', or in a directory mentioned in the variable +'treesit-extra-load-path'. + +You only need to install language grammar libraries required by the +Emacs modes you will use, as Emacs loads these libraries only when the +corresponding mode is turned on in some buffer for the first time in +an Emacs session. + +++ ** Emacs can be built with built-in support for accessing SQLite databases. This uses the popular sqlite3 library, and can be disabled by using diff --git a/lisp/emacs-lisp/advice.el b/lisp/emacs-lisp/advice.el index 080a6d84498..56f0ae2212c 100644 --- a/lisp/emacs-lisp/advice.el +++ b/lisp/emacs-lisp/advice.el @@ -1850,7 +1850,7 @@ function at point for which PREDICATE returns non-nil)." ad-advised-functions (if predicate (lambda (function) - (funcall predicate (intern (car function))))) + (funcall predicate (intern function)))) t))) (if (equal function "") (if (ad-is-advised default) diff --git a/lisp/eshell/esh-var.el b/lisp/eshell/esh-var.el index 27e68138aa2..83dd5cb50f5 100644 --- a/lisp/eshell/esh-var.el +++ b/lisp/eshell/esh-var.el @@ -467,9 +467,7 @@ process any indices that come after the variable reference." indices (and (not (eobp)) (eq (char-after) ?\[) (eshell-parse-indices)) - ;; This is an expression that will be evaluated by `eshell-do-eval', - ;; which only support let-binding of dynamically-scoped vars - value `(let ((indices (eshell-eval-indices ',indices))) ,value)) + value `(let ((indices ,(eshell-prepare-indices indices))) ,value)) (when get-len (setq value `(length ,value))) (when eshell-current-quoted @@ -496,7 +494,7 @@ Possible variable references are: NAME an environment or Lisp variable value \"LONG-NAME\" disambiguates the length of the name - `LONG-NAME' as above + \\='LONG-NAME\\=' as above {COMMAND} result of command is variable's value (LISP-FORM) result of Lisp form is variable's value write the output of command to a temporary file; @@ -591,7 +589,7 @@ Possible variable references are: "Parse and return a list of index-lists. For example, \"[0 1][2]\" becomes: - ((\"0\" \"1\") (\"2\")." + ((\"0\" \"1\") (\"2\"))." (let (indices) (while (eq (char-after) ?\[) (let ((end (eshell-find-delimiter ?\[ ?\]))) @@ -609,8 +607,14 @@ For example, \"[0 1][2]\" becomes: (defun eshell-eval-indices (indices) "Evaluate INDICES, a list of index-lists generated by `eshell-parse-indices'." + (declare (obsolete eshell-prepare-indices "30.1")) (mapcar (lambda (i) (mapcar #'eval i)) indices)) +(defun eshell-prepare-indices (indices) + "Prepare INDICES to be evaluated by Eshell. +INDICES is a list of index-lists generated by `eshell-parse-indices'." + `(list ,@(mapcar (lambda (idx-list) (cons 'list idx-list)) indices))) + (defun eshell-get-variable (name &optional indices quoted) "Get the value for the variable NAME. INDICES is a list of index-lists (see `eshell-parse-indices'). diff --git a/lisp/files.el b/lisp/files.el index 29ba523fa69..d308e99804d 100644 --- a/lisp/files.el +++ b/lisp/files.el @@ -7112,6 +7112,15 @@ each buffer, unless NO-ASK is non-nil." (string-match regexp name)) (funcall (if no-ask 'kill-buffer 'kill-buffer-ask) buffer))))) +(defun kill-matching-buffers-no-ask (regexp &optional internal-too) + "Kill buffers whose name matches the specified REGEXP. +Ignores buffers whose name starts with a space, unless optional +prefix argument INTERNAL-TOO is non-nil. Equivalent to +`kill-matching-buffers' but never ask before killing each +buffer." + (interactive "sKill buffers matching this regular expression: \nP") + (kill-matching-buffers regexp internal-too t)) + (defun rename-auto-save-file () "Adjust current buffer's auto save file name for current conditions. diff --git a/lisp/progmodes/cc-engine.el b/lisp/progmodes/cc-engine.el index 3fa407dd338..ebcb20f0f8c 100644 --- a/lisp/progmodes/cc-engine.el +++ b/lisp/progmodes/cc-engine.el @@ -10475,6 +10475,8 @@ This function might do hidden buffer changes." got-prefix ;; True if the declarator is surrounded by a parenthesis pair. got-parens + ;; True if there is a terminated argument list. + got-arglist ;; True if there is an identifier in the declarator. got-identifier ;; True if we find a number where an identifier was expected. @@ -10622,13 +10624,17 @@ This function might do hidden buffer changes." (when (> paren-depth 0) (setq paren-depth (1- paren-depth)) (forward-char) + (when (and (not got-parens) + (eq paren-depth 0)) + (setq got-arglist t)) t) - (when (if (save-match-data (looking-at "\\s(")) - (c-safe (c-forward-sexp 1) t) - (if (save-match-data - (looking-at c-fun-name-substitute-key)) ; requires - (c-forward-c++-requires-clause) - (goto-char (match-end 1)) + (when (cond + ((save-match-data (looking-at "\\s(")) + (c-safe (c-forward-sexp 1) t)) + ((save-match-data + (looking-at c-fun-name-substitute-key)) ; C++ requires + (c-forward-c++-requires-clause)) + (t (goto-char (match-end 1)) t)) (when (and (not got-suffix-after-parens) (= paren-depth 0)) @@ -10690,8 +10696,11 @@ This function might do hidden buffer changes." (goto-char pos) (setq pd (1- pd))) t))) - (c-fdoc-shift-type-backward) - t))) + (c-fdoc-shift-type-backward) + (when (and (not got-parens) + (eq paren-depth 0)) + (setq got-arglist t)) + t))) (c-forward-syntactic-ws)) @@ -10759,6 +10768,9 @@ This function might do hidden buffer changes." (not (or got-prefix got-parens))) ;; Got another identifier directly after the type, so it's a ;; declaration. + (when (and got-arglist + (eq at-type 'maybe)) + (setq unsafe-maybe t)) (throw 'at-decl-or-cast t)) (when (and got-parens @@ -11147,9 +11159,17 @@ This function might do hidden buffer changes." ;; inside an arglist that contains declarations. Update (2017-09): We ;; now recognize a top-level "foo(bar);" as a declaration in C. ;; CASE 19 - (or (eq context 'decl) - (and (c-major-mode-is 'c-mode) - (or (eq context 'top) make-top)))))) + (when + (or (eq context 'decl) + (and (c-major-mode-is 'c-mode) + (or (eq context 'top) make-top))) + (when (and (eq at-type 'maybe) + got-parens) + ;; If we've got "foo d(bar () ...)", the d could be a typing + ;; mistake, so we don't promote the 'maybe type "bar" to a 'found + ;; type. + (setq unsafe-maybe t)) + t)))) ;; The point is now after the type decl expression. diff --git a/lisp/progmodes/java-ts-mode.el b/lisp/progmodes/java-ts-mode.el index 83c437d307b..03093e09805 100644 --- a/lisp/progmodes/java-ts-mode.el +++ b/lisp/progmodes/java-ts-mode.el @@ -328,6 +328,21 @@ Return nil if there is no name or if NODE is not a defun node." "package_declaration" "import_declaration"))) + (setq-local treesit-sexp-type-regexp + (regexp-opt '("annotation" + "parenthesized_expression" + "argument_list" + "identifier" + "modifiers" + "block" + "body" + "literal" + "access" + "reference" + "_type" + "true" + "false"))) + ;; Font-lock. (setq-local treesit-font-lock-settings java-ts-mode--font-lock-settings) (setq-local treesit-font-lock-feature-list diff --git a/lisp/progmodes/ruby-mode.el b/lisp/progmodes/ruby-mode.el index 2e8d335f151..2de7395f765 100644 --- a/lisp/progmodes/ruby-mode.el +++ b/lisp/progmodes/ruby-mode.el @@ -1927,7 +1927,7 @@ If the result is do-end block, it will always be multiline." (end-of-line) (unless (if (and (re-search-backward "\\(?:[^#]\\)\\({\\)\\|\\(\\_\\)") - (progn + (let ((ruby-use-smie (and ruby-use-smie (consp smie-grammar)))) (goto-char (or (match-beginning 1) (match-beginning 2))) (setq beg (point)) (with-suppressed-warnings ((obsolete ruby-forward-sexp)) diff --git a/lisp/progmodes/ruby-ts-mode.el b/lisp/progmodes/ruby-ts-mode.el index f075824591d..f0337775d51 100644 --- a/lisp/progmodes/ruby-ts-mode.el +++ b/lisp/progmodes/ruby-ts-mode.el @@ -648,9 +648,6 @@ a statement container is a node that matches parent 0) ((match "\\." "call") parent ruby-indent-level) - ;; ruby-indent-after-block-in-continued-expression - ((match "begin" "assignment") parent ruby-indent-level) - ;; method parameters -- four styles: ;; 1) With paren, first arg on same line: ((and (query "(method_parameters \"(\" _ @indent)") @@ -680,7 +677,9 @@ a statement container is a node that matches ((and (query "(argument_list \"(\" _ @indent)") (node-is ")")) ruby-ts--parent-call-or-bol 0) - ((query "(argument_list \"(\" _ @indent)") + ((or (query "(argument_list \"(\" _ @indent)") + ;; No arguments yet; NODE is nil in that case. + (match "\\`\\'" "argument_list")) ruby-ts--parent-call-or-bol ruby-indent-level) ;; 3) No paren, ruby-parenless-call-arguments-indent is t ((and ruby-ts--parenless-call-arguments-indent-p (parent-is "argument_list")) @@ -704,10 +703,9 @@ a statement container is a node that matches ;; ruby-mode does not touch these... ((match "bare_string" "string_array") no-indent 0) - ;; hash and array other than assignments. Note that the - ;; first sibling is the "{" or "[". There is a special - ;; case where the hash is an argument to a method. These - ;; need to be processed first. + ;; hash and array. Note that the first sibling is the "{" + ;; or "[". There is a special case where the hash is an + ;; argument to a method. These need to be processed first. ((and ruby-ts--same-line-hash-array-p (match "}" "hash")) first-sibling 0) @@ -1008,6 +1006,20 @@ leading double colon is not added." ;; Navigation. (setq-local treesit-defun-type-regexp ruby-ts--method-regex) + (setq-local treesit-sexp-type-regexp + (regexp-opt '("class" + "module" + "method" + "argument_list" + "array" + "hash" + "parenthesized_statements" + "if" + "case" + "block" + "do_block" + "begin"))) + ;; AFAIK, Ruby can not nest methods (setq-local treesit-defun-prefer-top-level nil) diff --git a/lisp/treesit.el b/lisp/treesit.el index e8571d43db3..9d622de5580 100644 --- a/lisp/treesit.el +++ b/lisp/treesit.el @@ -1102,10 +1102,12 @@ See `treesit-simple-indent-presets'.") (string-match-p parent-t (treesit-node-type parent))) (or (null grand-parent-t) - (string-match-p - grand-parent-t - (treesit-node-type - (treesit-node-parent parent)))))))) + (and + (treesit-node-parent parent) + (string-match-p + grand-parent-t + (treesit-node-type + (treesit-node-parent parent))))))))) (cons 'no-node (lambda (node &rest _) (null node))) (cons 'parent-is (lambda (type) (lambda (_n parent &rest _) @@ -1636,6 +1638,21 @@ BACKWARD and ALL are the same as in `treesit-search-forward'." (goto-char current-pos))) node)) +(defvar-local treesit-sexp-type-regexp nil + "A regexp that matches the node type of sexp nodes. + +A sexp node is a node that is bigger than punctuation, and +delimits medium sized statements in the source code. It is, +however, smaller in scope than sentences. This is used by +`treesit-forward-sexp' and friends.") + +(defun treesit-forward-sexp (&optional arg) + (interactive "^p") + (or arg (setq arg 1)) + (funcall + (if (> arg 0) #'treesit-end-of-thing #'treesit-beginning-of-thing) + treesit-sexp-type-regexp (abs arg))) + (defun treesit-transpose-sexps (&optional arg) "Tree-sitter `transpose-sexps' function. Arg is the same as in `transpose-sexps'. @@ -2301,6 +2318,8 @@ before calling this function." (setq-local add-log-current-defun-function #'treesit-add-log-current-defun)) + (when treesit-sexp-type-regexp + (setq-local forward-sexp-function #'treesit-forward-sexp)) (setq-local transpose-sexps-function #'treesit-transpose-sexps) (when treesit-sentence-type-regexp (setq-local forward-sentence-function #'treesit-forward-sentence)) diff --git a/src/coding.c b/src/coding.c index 49dcd8634f3..79461addd1a 100644 --- a/src/coding.c +++ b/src/coding.c @@ -651,6 +651,12 @@ growable_destination (struct coding_system *coding) consumed_chars++; \ } while (0) +/* Suppress clang warnings about consumed_chars never being used. + Although correct, the warnings are too much trouble to code around. */ +#if 13 <= __clang_major__ +# pragma clang diagnostic ignored "-Wunused-but-set-variable" +#endif + /* Safely get two bytes from the source text pointed by SRC which ends at SRC_END, and set C1 and C2 to those bytes while skipping the heading multibyte characters. If there are not enough bytes in the diff --git a/test/lisp/eshell/esh-var-tests.el b/test/lisp/eshell/esh-var-tests.el index 0cc1b92266f..82324d72163 100644 --- a/test/lisp/eshell/esh-var-tests.el +++ b/test/lisp/eshell/esh-var-tests.el @@ -82,6 +82,17 @@ (eshell-command-result-equal "echo $eshell-test-value[0 2 4]" '("zero" "two" "four")))) +(ert-deftest esh-var-test/interp-var-indices-subcommand () + "Interpolate list variable with subcommand expansion for indices" + (skip-unless (executable-find "echo")) + (let ((eshell-test-value '("zero" "one" "two" "three" "four"))) + (eshell-command-result-equal + "echo $eshell-test-value[${*echo 0}]" + "zero") + (eshell-command-result-equal + "echo $eshell-test-value[${*echo 0} ${*echo 2}]" + '("zero" "two")))) + (ert-deftest esh-var-test/interp-var-split-indices () "Interpolate string variable with indices" (let ((eshell-test-value "zero one two three four")) @@ -271,6 +282,20 @@ (eshell-command-result-equal "echo \"$eshell-test-value[1 2 4]\"" "(\"one\" \"two\" \"four\")"))) +(ert-deftest esh-var-test/quote-interp-var-indices-subcommand () + "Interpolate list variable with subcommand expansion for indices +inside double-quotes" + (skip-unless (executable-find "echo")) + (let ((eshell-test-value '("zero" "one" "two" "three" "four"))) + (eshell-command-result-equal + "echo \"$eshell-test-value[${*echo 0}]\"" + "zero") + ;; FIXME: These tests would use the 0th index like the other tests + ;; here, but see above. + (eshell-command-result-equal + "echo \"$eshell-test-value[${*echo 1} ${*echo 2}]\"" + "(\"one\" \"two\")"))) + (ert-deftest esh-var-test/quoted-interp-var-split-indices () "Interpolate string variable with indices inside double-quotes" (let ((eshell-test-value "zero one two three four")) diff --git a/test/lisp/progmodes/ruby-ts-mode-tests.el b/test/lisp/progmodes/ruby-ts-mode-tests.el index d34c235e82b..18e3e60a04a 100644 --- a/test/lisp/progmodes/ruby-ts-mode-tests.el +++ b/test/lisp/progmodes/ruby-ts-mode-tests.el @@ -110,6 +110,18 @@ The whitespace before and including \"|\" on each line is removed." | 42 | end"))) + +(ert-deftest ruby-ts-indent-call-no-args () + (skip-unless (treesit-ready-p 'ruby t)) + (ruby-ts-with-temp-buffer + "variable = foo( + +)" + (goto-char (point-min)) + (forward-line 1) + (funcall indent-line-function) + (should (= (current-indentation) ruby-indent-level)))) + (ert-deftest ruby-ts-add-log-current-method-examples () (skip-unless (treesit-ready-p 'ruby t)) (let ((pairs '(("foo" . "#foo")