commit f45a776fe3c9160c49fdf21a96d37d2ed780836c (HEAD, refs/remotes/origin/master) Author: shipmints Date: Thu Jan 30 12:57:00 2025 -0500 Add new variable tab-bar-format-tab-help-text-function * lisp/tab-bar.el (tab-bar--format-tab): Add new variable 'tab-bar-format-tab-help-text-function' and a default function 'tab-bar-format-tab-help-text-default'. 'tab-bar--format-tab' respects this new variable when producing a tab's help text, normally shown in the echo area or via tooltips (bug#75950). diff --git a/etc/NEWS b/etc/NEWS index 7f6084490d8..2b1951c7b0b 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -256,6 +256,13 @@ This is useful to avoid key binding conflicts, such as when folding in outline mode using TAB keys, or when a user wants to define her own tab-bar keys without first having to remove the defaults. +--- +*** New variable 'tab-bar-format-tab-help-text-function'. +This variable may be overridden with a user-provided function to +customize help text for tabs displayed on the tab-bar. Help text is +normally shown in the echo area or via tooltips. See the variable's +docstring for arguments passed to a help-text function. + ** Project --- diff --git a/lisp/tab-bar.el b/lisp/tab-bar.el index 85a1bb59dc8..4b676ca89da 100644 --- a/lisp/tab-bar.el +++ b/lisp/tab-bar.el @@ -992,6 +992,17 @@ You can hide these buttons by customizing `tab-bar-format' and removing menu-item ,tab-bar-forward-button tab-bar-history-forward :help "Click to go forward in tab history")))) +(defun tab-bar-format-tab-help-text-default (tab _i) + (alist-get 'name tab)) + +(defvar tab-bar-format-tab-help-text-function #'tab-bar-format-tab-help-text-default + "Function to produce help text for tabs displayed in the tab bar. +This function should accept two arguments: the tab, and the one-based +tab's number. + +The function should produce a string, which may be propertized. By +default, use function `tab-bar-format-tab-help-text-default.") + (defun tab-bar--format-tab (tab i) "Format TAB using its index I and return the result as a keymap." (append @@ -1002,13 +1013,13 @@ You can hide these buttons by customizing `tab-bar-format' and removing menu-item ,(funcall tab-bar-tab-name-format-function tab i) ignore - :help ,(alist-get 'name tab)))) + :help ,(funcall tab-bar-format-tab-help-text-function tab i)))) (t `((,(intern (format "tab-%i" i)) menu-item ,(funcall tab-bar-tab-name-format-function tab i) ,(alist-get 'binding tab) - :help ,(alist-get 'name tab))))) + :help ,(funcall tab-bar-format-tab-help-text-function tab i))))) (when (alist-get 'close-binding tab) `((,(if (eq (car tab) 'current-tab) 'C-current-tab (intern (format "C-tab-%i" i))) commit 3479d42406b7952fe22917c14f9e1dd5522d364c Author: Yuan Fu Date: Thu Jan 30 21:16:39 2025 -0800 Add treesit-simple-indent-override-rules * lisp/treesit.el: (treesit-simple-indent-override-rules): New variable. (treesit-simple-indent): Try treesit-simple-indent-override-rules first. (treesit-add-simple-indent-rules): Mention the new variable. * etc/NEWS: Update news. diff --git a/etc/NEWS b/etc/NEWS index 9d0eb7b7d58..7f6084490d8 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -1163,6 +1163,10 @@ This variable allows major modes to setup Imenu for multiple languages. This new function makes it easier to customize indent rules for tree-sitter modes. +*** New variable 'treesit-simple-indent-override-rules' +Users can customize this variable to add simple custom indentation rules +for tree-sitter major modes. + +++ ** New optional BUFFER argument for 'string-pixel-width'. If supplied, 'string-pixel-width' will use any face remappings from diff --git a/lisp/treesit.el b/lisp/treesit.el index 1940dd37795..97fb2f478f2 100644 --- a/lisp/treesit.el +++ b/lisp/treesit.el @@ -1757,6 +1757,13 @@ should take the same argument as MATCHER or ANCHOR. If it matches, return a cons (ANCHOR-POS . OFFSET), where ANCHOR-POS is a position and OFFSET is the indent offset; if it doesn't match, return nil.") +(defvar-local treesit-simple-indent-override-rules nil + "Extra simple indent rules for customizing indentation. + +This variable should take the same form as +`treesit-simple-indent-rules'. Rules in this variable take precedence +over `treesit-simple-indent-rules'.") + (defun treesit--indent-prev-line-node (pos) "Return the largest node on the previous line of POS." (save-excursion @@ -2303,35 +2310,39 @@ OFFSET." (message "PARENT is nil, not indenting")) (cons nil nil)) (let* ((language (treesit-node-language parent)) - (rules (alist-get language - treesit-simple-indent-rules))) + (rules-list (list + (alist-get language + treesit-simple-indent-override-rules) + (alist-get language + treesit-simple-indent-rules)))) (catch 'match - (dolist (rule rules) - (if (functionp rule) - (let ((result (funcall rule node parent bol))) - (when result + (dolist (rules rules-list) + (dolist (rule rules) + (if (functionp rule) + (let ((result (funcall rule node parent bol))) + (when result + (when treesit--indent-verbose + (message "Matched rule: %S" rule)) + (throw 'match result))) + (let ((pred (nth 0 rule)) + (anchor (nth 1 rule)) + (offset (nth 2 rule))) + ;; Found a match. + (when (treesit--simple-indent-eval + (list pred node parent bol)) (when treesit--indent-verbose (message "Matched rule: %S" rule)) - (throw 'match result))) - (let ((pred (nth 0 rule)) - (anchor (nth 1 rule)) - (offset (nth 2 rule))) - ;; Found a match. - (when (treesit--simple-indent-eval - (list pred node parent bol)) - (when treesit--indent-verbose - (message "Matched rule: %S" rule)) - (let ((anchor-pos - (treesit--simple-indent-eval - (list anchor node parent bol))) - (offset-val - (cond ((numberp offset) offset) - ((and (symbolp offset) - (boundp offset)) - (symbol-value offset)) - (t (treesit--simple-indent-eval - (list offset node parent bol)))))) - (throw 'match (cons anchor-pos offset-val))))))) + (let ((anchor-pos + (treesit--simple-indent-eval + (list anchor node parent bol))) + (offset-val + (cond ((numberp offset) offset) + ((and (symbolp offset) + (boundp offset)) + (symbol-value offset)) + (t (treesit--simple-indent-eval + (list offset node parent bol)))))) + (throw 'match (cons anchor-pos offset-val)))))))) ;; Didn't find any match. (when treesit--indent-verbose (message "No matched rule")) @@ -2404,6 +2415,9 @@ RULES." (defun treesit-add-simple-indent-rules (language rules &optional where anchor) "Add simple indent RULES for LANGUAGE. +This function only affects `treesit-simple-indent-rules', +`treesit-simple-indent-override-rules' is not affected. + WHERE can be either :before or :after, which means adding RULES before or after the existing rules in `treesit-simple-indent-rules'. If ommited, default to adding the rules before (so it overrides existing commit ef28af35bb4c43d71fe4c10d02fe93f30e830c5e Author: Yuan Fu Date: Thu Jan 30 16:54:20 2025 -0800 Add treesit-add-simple-indent-rules * lisp/treesit.el: (treesit-add-simple-indent-rules): New function. * etc/NEWS: Update NEWS. * test/src/treesit-tests.el: (treesit-test-add-simple-indent-rules): Add a test for the new function. diff --git a/etc/NEWS b/etc/NEWS index 1e7365258a3..9d0eb7b7d58 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -1159,6 +1159,10 @@ at point to explore. *** New variable 'treesit-aggregated-simple-imenu-settings' This variable allows major modes to setup Imenu for multiple languages. +*** New function 'treesit-add-simple-indent-rules' +This new function makes it easier to customize indent rules for +tree-sitter modes. + +++ ** New optional BUFFER argument for 'string-pixel-width'. If supplied, 'string-pixel-width' will use any face remappings from diff --git a/lisp/treesit.el b/lisp/treesit.el index 76b6bdc9cb2..1940dd37795 100644 --- a/lisp/treesit.el +++ b/lisp/treesit.el @@ -2401,6 +2401,35 @@ RULES." offset))))) (cons lang (mapcar #'optimize-rule indent-rules))))) +(defun treesit-add-simple-indent-rules (language rules &optional where anchor) + "Add simple indent RULES for LANGUAGE. + +WHERE can be either :before or :after, which means adding RULES before +or after the existing rules in `treesit-simple-indent-rules'. If +ommited, default to adding the rules before (so it overrides existing +rules). + +If ANCHOR is non-nil, add RULES before/after the rules in +`treesit-simple-indent-rules' that's `equal' to ANCHOR. If ANCHOR is +omitted or no existing rules matches it, add RULES at the beginning or +end of existing rules." + (when (not (memq where '(nil :before :after))) + (error "WHERE must be either :before, :after, or nil")) + (let* ((existing-rules (alist-get language treesit-simple-indent-rules)) + (anchor-idx (and anchor (seq-position existing-rules anchor))) + (new-rules + (if anchor-idx + (let* ((pivot (if (eq where :after) + (1+ anchor-idx) + anchor-idx)) + (first-half (seq-subseq existing-rules 0 pivot)) + (second-half (seq-subseq existing-rules pivot))) + (append first-half rules second-half)) + (if (eq where :after) + (append existing-rules rules) + (append rules existing-rules))))) + (setf (alist-get language treesit-simple-indent-rules) new-rules))) + ;;; Search (defun treesit-search-forward-goto diff --git a/test/src/treesit-tests.el b/test/src/treesit-tests.el index f9c64f792d1..22f53243274 100644 --- a/test/src/treesit-tests.el +++ b/test/src/treesit-tests.el @@ -411,6 +411,27 @@ BODY is the test body." (let ((missing-bracket (treesit-node-child array -1))) (treesit-search-forward missing-bracket "" t)))) +;;; Indent + +(ert-deftest treesit-test-add-simple-indent-rules () + "Test `treesit-add-simple-indent-rules'." + (let ((treesit-simple-indent-rules + (copy-tree '((c (a a a) (b b b) (c c c)))))) + (treesit-add-simple-indent-rules 'c '((d d d))) + (should (equal treesit-simple-indent-rules + '((c (d d d) (a a a) (b b b) (c c c))))) + (treesit-add-simple-indent-rules 'c '((e e e)) :after) + (should (equal treesit-simple-indent-rules + '((c (d d d) (a a a) (b b b) (c c c) (e e e))))) + (treesit-add-simple-indent-rules 'c '((f f f)) :after '(b b b)) + (should (equal treesit-simple-indent-rules + '((c (d d d) (a a a) (b b b) (f f f) + (c c c) (e e e))))) + (treesit-add-simple-indent-rules 'c '((g g g)) :before '(b b b)) + (should (equal treesit-simple-indent-rules + '((c (d d d) (a a a) (g g g) + (b b b) (f f f) (c c c) (e e e))))))) + ;;; Query (defun treesit--ert-pred-last-sibling (node) commit a5965217fc1d7b56df60f8e798edd48ae52c8624 Author: shipmints Date: Thu Jan 30 07:20:34 2025 -0500 * lisp/tab-bar.el (tab-bar-select-tab): Fix wc-bl/wc-bbl when nil Remove the nil-check conditionals around 'wc-bl' and 'wc-bbl' that reset frame parameters 'buffer-list' and 'buried-buffer-list'. This ensures originating nil values correctly propagate (bug#75935). diff --git a/lisp/tab-bar.el b/lisp/tab-bar.el index 85b8e3da1bf..85a1bb59dc8 100644 --- a/lisp/tab-bar.el +++ b/lisp/tab-bar.el @@ -1669,8 +1669,8 @@ Negative TAB-NUMBER counts tabs from the end of the tab bar." (marker-buffer wc-point)) (goto-char wc-point)) - (when wc-bl (set-frame-parameter nil 'buffer-list wc-bl)) - (when wc-bbl (set-frame-parameter nil 'buried-buffer-list wc-bbl)) + (set-frame-parameter nil 'buffer-list wc-bl) + (set-frame-parameter nil 'buried-buffer-list wc-bbl) (when tab-bar-history-mode (puthash (selected-frame) commit 6c46e2a363195fea338bc89cdc8fa9a46b63e63a Author: shipmints Date: Wed Jan 29 13:43:04 2025 -0500 Add new user option tab-bar-define-keys * lisp/tab-bar.el (tab-bar-define-keys): Add new defcustom tab-bar-define-keys. Reorganize key binding functions to accommodate. Also remove checks for tab-bar-mode enabled in 'tab-bar-select-tab-modifiers', as unnecessary and which prevented user changes from being accepted in cases where the user defers enabling tab-bar-mode (bug#75918). diff --git a/etc/NEWS b/etc/NEWS index 2f1057a1307..1e7365258a3 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -245,6 +245,17 @@ This hook allows you to operate on a reopened tab. This is useful when you define custom tab parameters that may need adjustment when a tab is restored, and avoids advice. +--- +*** New user option 'tab-bar-define-keys'. +This controls which key bindings tab-bar creates. Values are t, the +default, which defines all keys and is backwards compatible, 'numeric' +(tab number selection only), 'tab' (TAB and SHIFT-TAB keys only), nil +(which defines none). + +This is useful to avoid key binding conflicts, such as when folding in +outline mode using TAB keys, or when a user wants to define her own +tab-bar keys without first having to remove the defaults. + ** Project --- diff --git a/lisp/tab-bar.el b/lisp/tab-bar.el index f220ee768ae..85b8e3da1bf 100644 --- a/lisp/tab-bar.el +++ b/lisp/tab-bar.el @@ -86,6 +86,35 @@ :group 'tab-bar-faces) + +(defvar tab-bar-mode-map (make-sparse-keymap) + "Tab Bar mode map.") + +(defcustom tab-bar-define-keys t + "Define specified tab-bar key bindings. +If t, the default, all key mappings are defined. + +If \\='numeric, define only numeric select-tab key mappings, and in +conjunction with `tab-bar-select-tab-modifiers', which see. + +If \\='tab, define only TAB and SHIFT-TAB tab-selection key mappings. + +If nil, do not define any key mappings. + +Customize this option, or use `setopt' to ensure it will take effect." + :type '(choice (const :tag "All keys" t) + (const :tag "Numeric tab selection keys" numeric) + (const :tag "TAB and SHIFT-TAB selection keys" tab) + (const :tag "None" nil)) + :initialize #'custom-initialize-default + :set (lambda (sym val) + (tab-bar--undefine-keys) + (set-default sym val) + ;; Enable the new keybindings + (tab-bar--define-keys)) + :group 'tab-bar + :version "31.1") + (defcustom tab-bar-select-tab-modifiers '() "List of modifier keys for selecting tab-bar tabs by their numbers. Possible modifier keys are `control', `meta', `shift', `hyper', `super' and @@ -104,18 +133,17 @@ For easier selection of tabs by their numbers, consider customizing (const alt)) :initialize #'custom-initialize-default :set (lambda (sym val) - (when tab-bar-mode - (tab-bar--undefine-keys)) + (tab-bar--undefine-keys) (set-default sym val) - ;; Reenable the tab-bar with new keybindings - (when tab-bar-mode - (tab-bar--define-keys))) + ;; Enable the new keybindings + (tab-bar--define-keys)) :group 'tab-bar :version "27.1") (defun tab-bar--define-keys () "Install key bindings to switch between tabs if so configured." - (when tab-bar-select-tab-modifiers + (when (and (memq tab-bar-define-keys '(t numeric)) + tab-bar-select-tab-modifiers) (define-key tab-bar-mode-map (vector (append tab-bar-select-tab-modifiers (list ?0))) #'tab-recent) @@ -128,6 +156,14 @@ For easier selection of tabs by their numbers, consider customizing (vector (append tab-bar-select-tab-modifiers (list ?9))) #'tab-last)) + (when (memq tab-bar-define-keys '(t tab)) + (unless (global-key-binding [(control tab)]) + (define-key tab-bar-mode-map [(control tab)] #'tab-next)) + (unless (global-key-binding [(control shift tab)]) + (define-key tab-bar-mode-map [(control shift tab)] #'tab-previous)) + (unless (global-key-binding [(control shift iso-lefttab)]) + (define-key tab-bar-mode-map [(control shift iso-lefttab)] #'tab-previous))) + ;; Replace default value with a condition that supports displaying ;; global-mode-string in the tab bar instead of the mode line. (when (and (memq 'tab-bar-format-global tab-bar-format) @@ -152,7 +188,11 @@ For easier selection of tabs by their numbers, consider customizing nil t)) (define-key tab-bar-mode-map (vector (append tab-bar-select-tab-modifiers (list ?9))) - nil t))) + nil t)) + + (define-key tab-bar-mode-map [(control tab)] nil t) + (define-key tab-bar-mode-map [(control shift tab)] nil t) + (define-key tab-bar-mode-map [(control shift iso-lefttab)] nil t)) (defun tab-bar--load-buttons () "Load the icons for the tab buttons." @@ -242,20 +282,6 @@ a list of frames to update." (if (and tab-bar-mode (eq tab-bar-show t)) 1 0)) (assq-delete-all 'tab-bar-lines default-frame-alist))))) -(defun tab-bar-mode--tab-key-bind (map key binding) - ;; Don't override user customized global key bindings - (define-key map key - `(menu-item "" ,binding - :filter ,(lambda (cmd) (unless (global-key-binding key) cmd))))) - -(defvar tab-bar-mode-map - (let ((map (make-sparse-keymap))) - (tab-bar-mode--tab-key-bind map [(control tab)] #'tab-next) - (tab-bar-mode--tab-key-bind map [(control shift tab)] #'tab-previous) - (tab-bar-mode--tab-key-bind map [(control shift iso-lefttab)] #'tab-previous) - map) - "Tab Bar mode map.") - (define-minor-mode tab-bar-mode "Toggle the tab bar in all graphical frames (Tab Bar mode). commit 815c4dc0e07cfae5398c6145a4b4887b7fa64f42 Author: shipmints Date: Tue Jan 28 18:24:15 2025 -0500 Add abnormal hook tab-bar-post-undo-close-tab-functions * lisp/tab-bar.el (tab-bar-undo-close-tab): Add new abnormal hook tab-bar-post-undo-close-tab-functions (bug#75919). diff --git a/etc/NEWS b/etc/NEWS index 09507adecb8..2f1057a1307 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -238,6 +238,13 @@ latter throws an error when the argument FRAME cannot be deleted. *** New abnormal hook 'tab-bar-auto-width-functions'. This hook allows you to control which tab-bar tabs are auto-resized. +--- +*** New abnormal hook 'tab-bar-post-undo-close-tab-functions'. +This hook allows you to operate on a reopened tab. + +This is useful when you define custom tab parameters that may need +adjustment when a tab is restored, and avoids advice. + ** Project --- diff --git a/lisp/tab-bar.el b/lisp/tab-bar.el index b570949bfec..f220ee768ae 100644 --- a/lisp/tab-bar.el +++ b/lisp/tab-bar.el @@ -2185,6 +2185,13 @@ happens interactively)." (unless tab-bar-mode (message "Deleted all other tabs"))))) +(defcustom tab-bar-post-undo-close-tab-functions nil + "List of functions to call after a closed tab is restored. +Each function is called with one argument: the tab that has been restored." + :type '(repeat function) + :group 'tab-bar + :version "31.1") + (defun tab-bar-undo-close-tab () "Restore the most recently closed tab." (interactive) @@ -2208,6 +2215,8 @@ happens interactively)." ;; `pushnew' handles the head of tabs but not frame-parameter (tab-bar-tabs-set tabs)) (tab-bar-select-tab (1+ index))) + (run-hook-with-args 'tab-bar-post-undo-close-tab-functions + tab) (tab-bar--update-tab-bar-lines)) (message "No more closed tabs to undo"))) commit f2e97338eb96739711f9d4cb308219ed3df46c06 Author: Eli Zaretskii Date: Thu Jan 30 14:03:20 2025 +0200 ; * lisp/progmodes/python.el (treesit-node-prev-sibling): Declare. diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el index bd8ec236207..f19fb708f0c 100644 --- a/lisp/progmodes/python.el +++ b/lisp/progmodes/python.el @@ -267,6 +267,7 @@ (declare-function treesit-node-start "treesit.c") (declare-function treesit-node-end "treesit.c") (declare-function treesit-node-parent "treesit.c") +(declare-function treesit-node-prev-sibling "treesit.c") ;; Avoid compiler warnings (defvar compilation-error-regexp-alist) commit a99ba59aa02ef8cfd314737950b6cd8d97015925 Author: Eli Zaretskii Date: Thu Jan 30 11:02:47 2025 +0200 ; * src/pdumper.c (dump_do_fixup): Pacify GCC. diff --git a/src/pdumper.c b/src/pdumper.c index 9f0447eb5aa..bfa790b963a 100644 --- a/src/pdumper.c +++ b/src/pdumper.c @@ -3990,7 +3990,7 @@ dump_do_fixup (struct dump_context *ctx, Lisp_Object arg = dump_pop (&fixup); eassert (NILP (fixup)); dump_seek (ctx, dump_fixup_offset); - intptr_t dump_value; + intptr_t dump_value UNINIT; bool do_write = true; switch (type) {