commit c146bd893dfbc8a4c92f9d1f33def8f29e7ece1f (HEAD, refs/remotes/origin/master) Author: Yuan Fu Date: Wed Apr 12 00:00:26 2023 -0700 Prompt target dir in treesit-install-language-grammar (bug#62704) * lisp/treesit.el (treesit--check-repo-url): New variable. (treesit-install-language-grammar): Prompt for target directory. diff --git a/lisp/treesit.el b/lisp/treesit.el index 9068a111489..3932920a962 100644 --- a/lisp/treesit.el +++ b/lisp/treesit.el @@ -3022,6 +3022,9 @@ treesit--check-repo-url (buffer-local-value 'url-http-response-status buffer) 200))))) +(defvar treesit--install-language-grammar-out-dir-history nil + "History for OUT-DIR for `treesit-install-language-grammar'.") + ;;;###autoload (defun treesit-install-language-grammar (lang) "Build and install the tree-sitter language grammar library for LANG. @@ -3043,11 +3046,20 @@ treesit-install-language-grammar (when-let ((recipe (or (assoc lang treesit-language-source-alist) (treesit--install-language-grammar-build-recipe - lang)))) + lang))) + (default-out-dir + (or (car treesit--install-language-grammar-out-dir-history) + (locate-user-emacs-file "tree-sitter"))) + (out-dir + (read-string + (format "Install to (default: %s): " + default-out-dir) + nil + 'treesit--install-language-grammar-out-dir-history + default-out-dir))) (condition-case err (apply #'treesit--install-language-grammar-1 - ;; The nil is OUT-DIR. - (cons nil recipe)) + (cons out-dir recipe)) (error (display-warning 'treesit commit 1a5a03c15abf4043cbbabaa5bcbb874fbef69505 Author: Yuan Fu Date: Thu Apr 6 14:47:51 2023 -0700 Define sexp in c-ts-mode more broadly (bug#62302) * lisp/progmodes/c-ts-mode.el: Define sexp in c/c++-ts-mode as anything but delimiters. diff --git a/lisp/progmodes/c-ts-mode.el b/lisp/progmodes/c-ts-mode.el index 385e3918842..ece20e90a6f 100644 --- a/lisp/progmodes/c-ts-mode.el +++ b/lisp/progmodes/c-ts-mode.el @@ -921,15 +921,13 @@ c-ts-base-mode "goto_statement" "case_statement"))) + ;; IMO it makes more sense to define what's NOT sexp, since sexp by + ;; spirit, especially when used for movement, is like "expression" + ;; or "syntax unit". --yuan (setq-local treesit-sexp-type-regexp - (regexp-opt '("preproc" - "declarator" - "qualifier" - "type" - "parameter" - "expression" - "literal" - "string"))) + ;; It more useful to include semicolons as sexp so that + ;; users can move to the end of a statement. + (rx (not (or "{" "}" "[" "]" "(" ")" ",")))) ;; Nodes like struct/enum/union_specifier can appear in ;; function_definitions, so we need to find the top-level node. commit 2ce27563ecc8d2427a24973d90ac4744aa3ae15f Author: Yuan Fu Date: Thu Apr 6 14:38:00 2023 -0700 Add 'restricted' tactic in tree-sitter navigation functions * lisp/treesit.el (treesit-forward-sexp): Add docstring. Use 'restricted' tactic. (treesit-transpose-sexps): Fix docstring. (treesit-beginning-of-thing) (treesit-end-of-thing): Add support for TACTIC. (treesit-beginning-of-defun) (treesit-end-of-defun): Supply treesit-defun-tactic as TACTIC. (treesit--navigate-thing): Add support for TACTIC. Wrap the old form in a new (if (eq tactic 'restricted) (new-code) (old-form)), and supply the TACTIC parameter when recursing. diff --git a/lisp/treesit.el b/lisp/treesit.el index 4c4ba4ad6ac..9068a111489 100644 --- a/lisp/treesit.el +++ b/lisp/treesit.el @@ -1783,15 +1783,17 @@ treesit-sexp-type-regexp `treesit-forward-sexp' and friends.") (defun treesit-forward-sexp (&optional arg) + "Tree-sitter implementation for `forward-sexp-function'. +ARG is described in the docstring of `forward-sexp-function'." (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))) + treesit-sexp-type-regexp (abs arg) 'restricted)) (defun treesit-transpose-sexps (&optional arg) "Tree-sitter `transpose-sexps' function. -Arg is the same as in `transpose-sexps'. +ARG is the same as in `transpose-sexps'. Locate the node closest to POINT, and transpose that node with its sibling node ARG nodes away. @@ -1896,33 +1898,53 @@ treesit--thing-unpack-pattern pattern (cons pattern nil))) -(defun treesit-beginning-of-thing (pattern &optional arg) +(defun treesit-beginning-of-thing (pattern &optional arg tactic) "Like `beginning-of-defun', but generalized into things. PATTERN is like `treesit-defun-type-regexp', ARG is the same as in `beginning-of-defun'. +TACTIC determines how does this function move between things. It +can be `nested', `top-level', `restricted', or nil. `nested' +means normal nested navigation: try to move to siblings first, +and if there aren't enough siblings, move to the parent and its +siblings. `top-level' means only consider top-level things, and +nested things are ignored. `restricted' means movement is +restricted inside the thing that encloses POS (i.e., parent), +should there be one. If omitted, TACTIC is considered to be +`nested'. + Return non-nil if successfully moved, nil otherwise." (pcase-let* ((arg (or arg 1)) (`(,regexp . ,pred) (treesit--thing-unpack-pattern pattern)) (dest (treesit--navigate-thing - (point) (- arg) 'beg regexp pred))) + (point) (- arg) 'beg regexp pred tactic))) (when dest (goto-char dest)))) -(defun treesit-end-of-thing (pattern &optional arg) +(defun treesit-end-of-thing (pattern &optional arg tactic) "Like `end-of-defun', but generalized into things. PATTERN is like `treesit-defun-type-regexp', ARG is the same as in `end-of-defun'. +TACTIC determines how does this function move between things. It +can be `nested', `top-level', `restricted', or nil. `nested' +means normal nested navigation: try to move to siblings first, +and if there aren't enough siblings, move to the parent and its +siblings. `top-level' means only consider top-level things, and +nested things are ignored. `restricted' means movement is +restricted inside the thing that encloses POS (i.e., parent), +should there be one. If omitted, TACTIC is considered to be +`nested'. + Return non-nil if successfully moved, nil otherwise." (pcase-let* ((arg (or arg 1)) (`(,regexp . ,pred) (treesit--thing-unpack-pattern pattern)) (dest (treesit--navigate-thing - (point) arg 'end regexp pred))) + (point) arg 'end regexp pred tactic))) (when dest (goto-char dest)))) @@ -1943,7 +1965,8 @@ treesit-beginning-of-defun (catch 'done (dotimes (_ 2) - (when (treesit-beginning-of-thing treesit-defun-type-regexp arg) + (when (treesit-beginning-of-thing + treesit-defun-type-regexp arg treesit-defun-tactic) (when treesit-defun-skipper (funcall treesit-defun-skipper) (setq success t))) @@ -1971,7 +1994,8 @@ treesit-end-of-defun (catch 'done (dotimes (_ 2) ; Not making progress is better than infloop. - (when (treesit-end-of-thing treesit-defun-type-regexp arg) + (when (treesit-end-of-thing + treesit-defun-type-regexp arg treesit-defun-tactic) (when treesit-defun-skipper (funcall treesit-defun-skipper))) @@ -2144,7 +2168,7 @@ treesit--top-level-thing ;; -> Obviously we don't want to go to parent's end, instead, we ;; want to go to parent's prev-sibling's end. Again, we recurse ;; in the function to do that. -(defun treesit--navigate-thing (pos arg side regexp &optional pred recursing) +(defun treesit--navigate-thing (pos arg side regexp &optional pred tactic recursing) "Navigate thing ARG steps from POS. If ARG is positive, move forward that many steps, if negative, @@ -2157,6 +2181,16 @@ treesit--navigate-thing REGEXP and PRED are the same as in `treesit-thing-at-point'. +TACTIC determines how does this function move between things. It +can be `nested', `top-level', `restricted', or nil. `nested' +means normal nested navigation: try to move to siblings first, +and if there aren't enough siblings, move to the parent and its +siblings. `top-level' means only consider top-level things, and +nested things are ignored. `restricted' means movement is +restricted inside the thing that encloses POS (i.e., parent), +should there be one. If omitted, TACTIC is considered to be +`nested'. + RECURSING is an internal parameter, if non-nil, it means this function is called recursively." (pcase-let* @@ -2178,53 +2212,57 @@ treesit--navigate-thing ;; When PARENT is nil, nested and top-level are the same, if ;; there is a PARENT, make PARENT to be the top-level parent ;; and pretend there is no nested PREV and NEXT. - (when (and (eq treesit-defun-tactic 'top-level) + (when (and (eq tactic 'top-level) parent) (setq parent (treesit--top-level-thing parent regexp pred) prev nil next nil)) - ;; Move... - (if (> arg 0) - ;; ...forward. - (if (and (eq side 'beg) - ;; Should we skip the defun (recurse)? - (cond (next (and (not recursing) ; [1] (see below) - (eq pos (funcall advance next)))) - (parent t))) ; [2] - ;; Special case: go to next beg-of-defun, but point - ;; is already on beg-of-defun. Set POS to the end - ;; of next-sib/parent defun, and run one more step. - ;; If there is a next-sib defun, we only need to - ;; recurse once, so we don't need to recurse if we - ;; are already recursing [1]. If there is no - ;; next-sib but a parent, keep stepping out - ;; (recursing) until we got out of the parents until - ;; (1) there is a next sibling defun, or (2) no more - ;; parents [2]. - ;; - ;; If point on beg-of-defun but we are already - ;; recurring, that doesn't count as special case, - ;; because we have already made progress (by moving - ;; the end of next before recurring.) + ;; If TACTIC is `restricted', the implementation is very simple. + (if (eq tactic 'restricted) + (setq pos (funcall advance (if (> arg 0) next prev))) + ;; For `nested', it's a bit more work: + ;; Move... + (if (> arg 0) + ;; ...forward. + (if (and (eq side 'beg) + ;; Should we skip the defun (recurse)? + (cond (next (and (not recursing) ; [1] (see below) + (eq pos (funcall advance next)))) + (parent t))) ; [2] + ;; Special case: go to next beg-of-defun, but point + ;; is already on beg-of-defun. Set POS to the end + ;; of next-sib/parent defun, and run one more step. + ;; If there is a next-sib defun, we only need to + ;; recurse once, so we don't need to recurse if we + ;; are already recursing [1]. If there is no + ;; next-sib but a parent, keep stepping out + ;; (recursing) until we got out of the parents until + ;; (1) there is a next sibling defun, or (2) no more + ;; parents [2]. + ;; + ;; If point on beg-of-defun but we are already + ;; recurring, that doesn't count as special case, + ;; because we have already made progress (by moving + ;; the end of next before recurring.) + (setq pos (or (treesit--navigate-thing + (treesit-node-end (or next parent)) + 1 'beg regexp pred tactic t) + (throw 'term nil))) + ;; Normal case. + (setq pos (funcall advance (or next parent)))) + ;; ...backward. + (if (and (eq side 'end) + (cond (prev (and (not recursing) + (eq pos (funcall advance prev)))) + (parent t))) + ;; Special case: go to prev end-of-defun. (setq pos (or (treesit--navigate-thing - (treesit-node-end (or next parent)) - 1 'beg regexp pred t) + (treesit-node-start (or prev parent)) + -1 'end regexp pred tactic t) (throw 'term nil))) ;; Normal case. - (setq pos (funcall advance (or next parent)))) - ;; ...backward. - (if (and (eq side 'end) - (cond (prev (and (not recursing) - (eq pos (funcall advance prev)))) - (parent t))) - ;; Special case: go to prev end-of-defun. - (setq pos (or (treesit--navigate-thing - (treesit-node-start (or prev parent)) - -1 'end regexp pred t) - (throw 'term nil))) - ;; Normal case. - (setq pos (funcall advance (or prev parent))))) + (setq pos (funcall advance (or prev parent)))))) ;; A successful step! Decrement counter. (cl-decf counter)))) ;; Counter equal to 0 means we successfully stepped ARG steps. commit e54feef094a273cea28c980df57de0808cc7ef30 Author: Andrew G Cohen Date: Wed Apr 12 08:13:23 2023 +0800 Expunge immediately when moving articles from nnimap groups * lisp/gnus/nnselect.el (nnselect-request-move-article): Set nnimap-expunge to immediately. diff --git a/lisp/gnus/nnselect.el b/lisp/gnus/nnselect.el index af4dbdc35df..57a833de9bf 100644 --- a/lisp/gnus/nnselect.el +++ b/lisp/gnus/nnselect.el @@ -478,7 +478,8 @@ nnselect-request-article (deffoo nnselect-request-move-article (article _group _server accept-form &optional last _internal-move-group) - (let* ((artgroup (nnselect-article-group article)) + (let* ((nnimap-expunge 'immediately) + (artgroup (nnselect-article-group article)) (artnumber (nnselect-article-number article)) (to-newsgroup (nth 1 accept-form)) (to-method (gnus-find-method-for-group to-newsgroup)) commit b3a44ff3247dff54659f9f61daf297d3bdc8e2f4 Author: Dmitry Gutov Date: Wed Apr 12 02:27:51 2023 +0300 ruby-ts-mode: Do not treat parenless calls' args as separate sexp * lisp/progmodes/ruby-ts-mode.el (ruby-ts--sexp-p): New function. (ruby-ts-mode): Use it in treesit-sexp-type-regexp (bug#62086). diff --git a/lisp/progmodes/ruby-ts-mode.el b/lisp/progmodes/ruby-ts-mode.el index ddf2ee98c3b..7a00977f14a 100644 --- a/lisp/progmodes/ruby-ts-mode.el +++ b/lisp/progmodes/ruby-ts-mode.el @@ -1086,6 +1086,15 @@ ruby-ts--syntax-propertize (put-text-property pos (1+ pos) 'syntax-table (string-to-syntax "!")))))))) +(defun ruby-ts--sexp-p (node) + ;; Skip parenless calls (implicit parens are both non-obvious to the + ;; user, and might take over when we want to just over some physical + ;; parens/braces). + (or (not (equal (treesit-node-type node) + "argument_list")) + (equal (treesit-node-type (treesit-node-child node 0)) + "("))) + (defvar-keymap ruby-ts-mode-map :doc "Keymap used in Ruby mode" :parent prog-mode-map @@ -1114,8 +1123,10 @@ ruby-ts-mode (setq-local treesit-defun-type-regexp ruby-ts--method-regex) (setq-local treesit-sexp-type-regexp - (rx bol - (or "class" + (cons (rx + bol + (or + "class" "module" "method" "array" @@ -1147,7 +1158,8 @@ ruby-ts-mode "instance_variable" "global_variable" ) - eol)) + eol) + #'ruby-ts--sexp-p)) ;; AFAIK, Ruby can not nest methods (setq-local treesit-defun-prefer-top-level nil) commit 560950468588117b264a9f916fb578e0eb2a124a Author: João Távora Date: Tue Apr 11 13:35:43 2023 +0100 Flymake: take advantage of new Eldoc options Only echo the first line of a potentially very large error message. * lisp/progmodes/flymake.el: (flymake-diagnostic-oneliner): New helper. (flymake--tabulated-entries-1) (flymake-eldoc-function): Use it. (Version): Bump to 1.3.2. (Package-Requires): Use Eldoc 1.14.0. diff --git a/lisp/progmodes/flymake.el b/lisp/progmodes/flymake.el index a352adbba19..1cd9f0a6b0c 100644 --- a/lisp/progmodes/flymake.el +++ b/lisp/progmodes/flymake.el @@ -4,9 +4,9 @@ ;; Author: Pavel Kobyakov ;; Maintainer: João Távora -;; Version: 1.2.2 +;; Version: 1.3.2 ;; Keywords: c languages tools -;; Package-Requires: ((emacs "26.1") (eldoc "1.1.0") (project "0.7.1")) +;; Package-Requires: ((emacs "26.1") (eldoc "1.14.0") (project "0.7.1")) ;; This is a GNU ELPA :core package. Avoid functionality that is not ;; compatible with the version of Emacs recorded above. @@ -371,6 +371,12 @@ flymake--diag-accessor (flymake--diag-accessor flymake-diagnostic-end flymake--diag-end end) (flymake--diag-accessor flymake-diagnostic-buffer flymake--diag-locus locus) +(defun flymake-diagnostic-oneliner (diag) + "Get truncated one-line text string for diagnostic DIAG." + (let ((txt (flymake-diagnostic-text diag))) + (substring txt 0 (cl-loop for i from 0 for a across txt + when (eq a ?\n) return i)))) + (cl-defun flymake--overlays (&key beg end filter compare key) "Get flymake-related overlays. If BEG is non-nil and END is nil, consider only `overlays-at' @@ -1254,10 +1260,17 @@ flymake-find-file-hook (defun flymake-eldoc-function (report-doc &rest _) "Document diagnostics at point. Intended for `eldoc-documentation-functions' (which see)." - (let ((diags (flymake-diagnostics (point)))) - (when diags - (funcall report-doc - (mapconcat #'flymake-diagnostic-text diags "\n"))))) + (when-let ((diags (flymake-diagnostics (point)))) + (funcall report-doc + (mapconcat #'flymake-diagnostic-text diags "\n") + :echo (mapconcat (lambda (d) + (propertize (flymake-diagnostic-oneliner d) + 'face + (flymake--lookup-type-property + (flymake-diagnostic-type d) + 'face + 'flymake-error))) + diags "\n")))) (defun flymake-goto-next-error (&optional n filter interactive) "Go to Nth next Flymake diagnostic that matches FILTER. @@ -1582,8 +1595,7 @@ flymake--tabulated-entries-1 "\\1\\2" bname) "(anon)") 'help-echo (format "From `%s' backend" backend)) - (,(replace-regexp-in-string "\n.*" "" - (flymake-diagnostic-text diag)) + (,(flymake-diagnostic-oneliner diag) mouse-face highlight help-echo "mouse-2: visit this diagnostic" face nil commit fb66e4d58bbc24abf44157078e8ca51ffed93113 Author: Mattias Engdegård Date: Tue Apr 11 11:57:07 2023 +0200 nndiary.el: fix dodgy schedule code * lisp/gnus/nndiary.el (nndiary-last-occurrence): Don't sort a list and throw away the result because that leaves the list variable in an undefined state. Just take the largest element because that was obviously what the author meant. diff --git a/lisp/gnus/nndiary.el b/lisp/gnus/nndiary.el index be2bdc9bb15..8728aab1def 100644 --- a/lisp/gnus/nndiary.el +++ b/lisp/gnus/nndiary.el @@ -1373,10 +1373,10 @@ nndiary-last-occurrence (setq day (+ 7 day)))) ;; Finally, if we have some days, they are valid (when days - (sort days #'>) (throw 'found (encode-time 0 minute hour - (car days) month year time-zone))) + (apply #'max days) + month year time-zone))) ))))) ;; There's an upper limit, but we didn't find any last occurrence. ;; This means that the schedule is undecidable. This can happen if commit 5dab172a17320e93332ae6545738b37f4224f2de Author: Mattias Engdegård Date: Tue Apr 11 11:50:17 2023 +0200 allout.el: fix subtree expose numbering bug * lisp/allout.el (allout-process-exposed): Reverse the list of indices properly so that the correct numbering for nodes in a subtree is used. Avoid destructive reversing; the list may be a constant (literal). This flaw was revealed by an ignored-return-value warning. diff --git a/lisp/allout.el b/lisp/allout.el index 4d5d814ae01..be2fd632c69 100644 --- a/lisp/allout.el +++ b/lisp/allout.el @@ -5390,7 +5390,7 @@ allout-process-exposed ;; not specified -- default it: (setq tobuf (concat "*" (buffer-name frombuf) " exposed*"))) (if (listp format) - (nreverse format)) + (setq format (reverse format))) (let* ((listified (progn (set-buffer frombuf)