From d8ba28fa3943b73b748b3f50853031139f23ef9b Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Mon, 29 May 2023 15:32:51 +0300 Subject: [PATCH 01/23] Fix order of tmm-menubar when 'tmm-mid-prompt' is nil * lisp/tmm.el (tmm-prompt): Reverse 'tmm-km-list' when 'tmm-mid-prompt' is nil, to present the menu in the correct order. Suggested by Thiago Melo . --- lisp/tmm.el | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lisp/tmm.el b/lisp/tmm.el index 6088961fa4c..88254f0d1b8 100644 --- a/lisp/tmm.el +++ b/lisp/tmm.el @@ -170,9 +170,11 @@ instead of executing it." (error "Empty menu reached")) (and tmm-km-list (let ((index-of-default 0)) - (if tmm-mid-prompt - (setq tmm-km-list (tmm-add-shortcuts tmm-km-list)) - t) + (setq tmm-km-list + (if tmm-mid-prompt + (tmm-add-shortcuts tmm-km-list) + ;; tmm-add-shortcuts reverses tmm-km-list internally. + (reverse tmm-km-list))) ;; Find the default item's index within the menu bar. ;; We use this to decide the initial minibuffer contents ;; and initial history position. From a3063f0bc873707c167cf51f3eb9c0b1675819e6 Mon Sep 17 00:00:00 2001 From: Robert Pluim Date: Tue, 25 Apr 2023 12:27:00 +0200 Subject: [PATCH 02/23] Add a binding for enriched-toggle-markup * lisp/textmodes/enriched.el (enriched-mode-map): Bind 'enriched-toggle-markup' to 'M-o m'. * etc/NEWS: Announce the change. --- etc/NEWS | 2 +- lisp/textmodes/enriched.el | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/etc/NEWS b/etc/NEWS index a3457d70340..e33e40d9009 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -1769,7 +1769,7 @@ or can take a long time to render. +++ *** New command 'enriched-toggle-markup'. This allows you to see the markup in 'enriched-mode' buffers (e.g., -the "HELLO" file). +the "HELLO" file). Bound to 'M-o m' by default. ** Shell Script Mode diff --git a/lisp/textmodes/enriched.el b/lisp/textmodes/enriched.el index ec3046decd4..92be5a52bf2 100644 --- a/lisp/textmodes/enriched.el +++ b/lisp/textmodes/enriched.el @@ -192,6 +192,7 @@ The value is a list of \(VAR VALUE VAR VALUE...).") (define-key map "\C-c[" #'set-left-margin) (define-key map "\C-c]" #'set-right-margin) (define-key map "\M-o" #'facemenu-keymap) + (define-key map "\M-om" #'enriched-toggle-markup) map) "Keymap for Enriched mode.") From 08104c01504f73d1c2fa7df413cad4e988dd5119 Mon Sep 17 00:00:00 2001 From: Robert Pluim Date: Tue, 25 Apr 2023 12:28:47 +0200 Subject: [PATCH 03/23] Allow dired to invoke secondary browser 'browse-url-of-dired-file' always invokes the primary browser, but sometimes it's handy to call a different browser, which is why 'browse-url-secondary-browser-function' exists. * lisp/net/browse-url.el (browse-url-of-dired-file): Call 'browse-url-secondary-browser-function' when invoked with a prefix argument. * etc/NEWS: Announce the change. --- etc/NEWS | 7 +++++++ lisp/net/browse-url.el | 13 ++++++++++--- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/etc/NEWS b/etc/NEWS index e33e40d9009..7785d734a6f 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -1692,6 +1692,13 @@ the following to your Init file: *** New command 'dired-do-eww'. This command visits the file on the current line with EWW. +--- +*** 'browse-url-of-dired-file' can now call the secondary browser. +When invoked with a prefix arg, this will now call +'browse-url-secondary-browser-function' instead of the default +browser. 'browse-url-of-dired-file' is bound to 'W' by default in +dired mode. + --- *** New user option 'dired-omit-lines'. This is used by 'dired-omit-mode', and now allows you to hide based on diff --git a/lisp/net/browse-url.el b/lisp/net/browse-url.el index 0177d12f236..39513b8f602 100644 --- a/lisp/net/browse-url.el +++ b/lisp/net/browse-url.el @@ -825,10 +825,17 @@ If optional arg TEMP-FILE-NAME is non-nil, delete it instead." (&optional localp no-error-if-not-filep)) ;;;###autoload -(defun browse-url-of-dired-file () - "In Dired, ask a WWW browser to display the file named on this line." - (interactive) +(defun browse-url-of-dired-file (&optional secondary) + "In Dired, ask a WWW browser to display the file named on this line. +With prefix arg, use the secondary browser instead (e.g. EWW if +`browse-url-secondary-browser-function' is set to +`eww-browse-url'." + (interactive "P") (let ((tem (dired-get-filename t t)) + (browse-url-browser-function + (if secondary + browse-url-secondary-browser-function + browse-url-browser-function)) ;; Some URL handlers open files in Emacs. We want to always ;; open in a browser, so disable those. (browse-url-default-handlers nil)) From afc1f329356da167902d86b610023a32943f6cee Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Mon, 29 May 2023 16:44:48 +0300 Subject: [PATCH 04/23] Allow to disable the DWIMish behavior of 'x' in package menu * lisp/emacs-lisp/package.el (package-menu-use-current-if-no-marks): New defcustom. (package-menu-execute): Use it. (Bug#62563) * etc/NEWS: Announce the new option. --- etc/NEWS | 4 +++- lisp/emacs-lisp/package.el | 15 ++++++++++++++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/etc/NEWS b/etc/NEWS index 7785d734a6f..60aa64b5ede 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -1886,7 +1886,9 @@ These commands can be useful if the ".elc" files are out of date +++ *** New DWIM action on 'x' in "*Packages*" buffer. If no packages are marked, 'x' will install the package under point if -it isn't already, and remove it if it is installed. +it isn't already, and remove it if it is installed. Customize the new +option 'package-menu-use-current-if-no-marks' to the nil value to get +back the old behavior of signaling an error in that case. +++ *** New command 'package-vc-install'. diff --git a/lisp/emacs-lisp/package.el b/lisp/emacs-lisp/package.el index 340ca9400fa..202aca36f24 100644 --- a/lisp/emacs-lisp/package.el +++ b/lisp/emacs-lisp/package.el @@ -3313,6 +3313,18 @@ Values can be interactively added to this list by typing :version "25.1" :type '(repeat (regexp :tag "Hide packages with name matching"))) +(defcustom package-menu-use-current-if-no-marks t + "Whether \\\\[package-menu-execute] in package menu operates on current package if none are marked. + +If non-nil, and no packages are marked for installation or +deletion, \\\\[package-menu-execute] will operate on the current package at point, +see `package-menu-execute' for details. +The default is t. Set to nil to get back the original behavior +of having `package-menu-execute' signal an error when no packages +are marked for installation or deletion." + :version "29.1" + :type 'boolean) + (defun package-menu--refresh (&optional packages keywords) "Re-populate the `tabulated-list-entries'. PACKAGES should be nil or t, which means to display all known packages. @@ -3943,7 +3955,8 @@ invocations." ;; Nothing marked. (unless (or delete-list install-list) ;; Not on a package line. - (unless (tabulated-list-get-id) + (unless (and (tabulated-list-get-id) + package-menu-use-current-if-no-marks) (user-error "No operations specified")) (let* ((id (tabulated-list-get-id)) (status (package-menu-get-status))) From 500abc4dc3792d9f5e1bfdbb5e493c8a59889097 Mon Sep 17 00:00:00 2001 From: Juri Linkov Date: Mon, 29 May 2023 20:34:53 +0300 Subject: [PATCH 05/23] * lisp/tmm.el (tmm-completion-delete-prompt): Add more checks (bug#63754). In case when 'completions-header-format' is nil, the first 'mouse-face' property is at the beginning of the buffer. So first use 'get-text-property' at point-min. --- lisp/tmm.el | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lisp/tmm.el b/lisp/tmm.el index 88254f0d1b8..a4058594622 100644 --- a/lisp/tmm.el +++ b/lisp/tmm.el @@ -329,7 +329,8 @@ Stores a list of all the shortcuts in the free variable `tmm-short-cuts'." (with-current-buffer standard-output (goto-char (point-min)) (let* (;; First candidate: first string with mouse-face - (menu-start-1 (next-single-char-property-change (point) 'mouse-face)) + (menu-start-1 (or (and (get-text-property (point) 'mouse-face) (point)) + (next-single-char-property-change (point) 'mouse-face))) ;; Second candidate: an inactive menu item with tmm-inactive face (tps-result (save-excursion (text-property-search-forward 'face 'tmm-inactive t))) From 23a14e7b9026a8572fe8ae8759232e08cd37910a Mon Sep 17 00:00:00 2001 From: Theodor Thornhill Date: Tue, 30 May 2023 15:29:38 +0200 Subject: [PATCH 06/23] Add compact_constructor_declaration font-locking to java-ts-mode * lisp/progmodes/java-ts-mode.el (java-ts-mode--font-lock-settings): New pattern. --- lisp/progmodes/java-ts-mode.el | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lisp/progmodes/java-ts-mode.el b/lisp/progmodes/java-ts-mode.el index fca00cdce4f..44dfd74cafd 100644 --- a/lisp/progmodes/java-ts-mode.el +++ b/lisp/progmodes/java-ts-mode.el @@ -226,6 +226,9 @@ the available version of Tree-sitter for java." (constructor_declaration name: (identifier) @font-lock-type-face) + (compact_constructor_declaration + name: (identifier) @font-lock-type-face) + (field_access object: (identifier) @font-lock-type-face) From 372bc1278c2d7c2440bb3d528f4c4e03402d21b5 Mon Sep 17 00:00:00 2001 From: Jens Schmidt Date: Sun, 21 May 2023 21:37:35 +0200 Subject: [PATCH 07/23] Add internal documentation on plstore.el * lisp/plstore.el: Add internal documentation and some words of warning in the user documentation. (Bug#63627) --- lisp/plstore.el | 133 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 131 insertions(+), 2 deletions(-) diff --git a/lisp/plstore.el b/lisp/plstore.el index 0276a752a0f..1a0dacffb01 100644 --- a/lisp/plstore.el +++ b/lisp/plstore.el @@ -24,6 +24,14 @@ ;; Plist based data store providing search and partial encryption. ;; +;; By default, this package uses symmetric encryption, which means +;; that you have to enter the password protecting your store more +;; often than you probably expect to. To use public key encryption +;; with this package, create a GnuPG key and customize user option +;; `plstore-encrypt-to' to use it. You can then configure the GnuPG +;; agent to adjust caching and expiration of the passphrase for your +;; store. +;; ;; Creating: ;; ;; ;; Open a new store associated with ~/.emacs.d/auth.plist. @@ -43,12 +51,16 @@ ;; ;; Kill the buffer visiting ~/.emacs.d/auth.plist. ;; (plstore-close store) ;; +;; Avoid marking one property both as public *and* secret, as the +;; behavior of this package with respect to such duplicate properties +;; is not (yet) defined. +;; ;; Searching: ;; ;; (setq store (plstore-open (expand-file-name "~/.emacs.d/auth.plist"))) ;; ;; ;; As the entry "foo" associated with "foo.example.org" has no -;; ;; secret properties, no need to decryption. +;; ;; secret properties, no need for decryption. ;; (plstore-find store '(:host ("foo.example.org"))) ;; ;; ;; As the entry "bar" associated with "bar.example.org" has a @@ -73,10 +85,112 @@ ;; ;; where the prefixing `:secret-' means the property (without ;; `:secret-' prefix) is marked as secret. Thus, when you save the -;; buffer, the `:secret-user' property is encrypted as `:user'. +;; buffer, the `:secret-user' property is encrypted as `:user'. Do +;; not use a property consisting solely of the prefix, as the behavior +;; of this package with respect to such properties is not (yet) +;; defined. ;; ;; You can toggle the view between encrypted form and the decrypted ;; form with C-c C-c. +;; +;; If you have opened a plstore with `plstore-open' you should not +;; edit its underlying buffer in `plstore-mode' or in any other way at +;; the same time, since your manual changes will be overwritten when +;; `plstore-save' is called on that plstore. +;; +;; Internals: +;; +;; This is information on the internal data structure and functions of +;; this package. None of it should be necessary to actually use it. +;; For easier reading, we usually do not distinguish in this internal +;; documentation between a Lisp object and its printed representation. +;; +;; A plstore corresponds to an alist mapping strings to property +;; lists. Internally, that alist is organized as two alists, one +;; mapping to the non-secret properties and placeholders for the +;; secret properties (called "template alist" with identifier ALIST) +;; and one mapping to the secret properties ("secret alist", +;; SECRET-ALIST). The secret alist is read from and written to file +;; as pgp-encrypted printed representation of the alist ("encrypted +;; data", ENCRYPTED-DATA). +;; +;; During the lifetime of a plstore, a third type of alist may pop up, +;; which maps to the merged non-secret properties and plain-text +;; secret properties ("merged alist", MERGED-ALIST). +;; +;; After executing the "foo", "bar", "baz" example from above the +;; alists described above look like the following: +;; +;; Template Alist: +;; +;; (("foo" :host "foo.example.org" :port 80) +;; ("bar" :secret-user t :host "bar.example.org") +;; ("baz" :secret-password t :host "baz.example.org")) +;; +;; Secret Alist: +;; +;; (("bar" :user "test") +;; ("baz" :password "test")) +;; +;; Merged Alist: +;; +;; (("foo" :host "foo.example.org" :port 80) +;; ("bar" :user "test" :host "bar.example.org") +;; ("baz" :password "test" :host "baz.example.org")) +;; +;; Finally, a plstore requires a buffer ("plstore buffer", BUFFER) for +;; conversion between its Lisp objects and its file representation. +;; It is important to note that this buffer is *not* continuously +;; synchronized as the plstore changes. During the lifetime of a +;; plstore, its buffer is read from in function `plstore-open' and +;; (destructively) written to in `plstore-save', but not touched +;; otherwise. We call the file visited by the plstore buffer the +;; associated file of the plstore. +;; +;; With the identifiers defined above a plstore is a vector with the +;; following elements and accessor functions: +;; +;; [ +;; BUFFER ; plstore--get/set-buffer +;; ALIST ; plstore--get/set-alist +;; ENCRYPTED-DATA ; plstore--get/set-encrypted-data +;; SECRET-ALIST ; plstore--get/set-secret-alist +;; MERGED-ALIST ; plstore--get/set-merged-alist +;; ] +;; +;; When a plstore is created through `plstore-open', its ALIST and +;; ENCRYPTED-DATA are initialized from the contents of BUFFER without +;; any decryption taking place, and MERGED-ALIST is initialized as a +;; copy of ALIST. (Which means that at that stage the merged alist +;; still contains the secret property placeholders!) +;; +;; During on-demand decryption of a plstore through function +;; `plstore--decrypt', SECRET-ALIST is populated from ENCRYPTED-DATA, +;; which is in turn replaced by value nil. (Which further serves as +;; an indicator that the plstore has been decrypted already.) In +;; addition, MERGED-ALIST is recomputed by function +;; `plstore--merge-secret' to replace the secret property placeholders +;; by their plain-text secret property equivalents. +;; +;; The file representation of a plstore consists of two Lisp forms plus +;; markers to introduce them: +;; +;; ;;; public entries +;; ALIST +;; ;;; secret entries +;; ENCRYPTED-DATA +;; +;; Both of these are optional, but the first section must be present +;; if the second one is. If both sections are missing, the plstore is +;; empty. If the second section is missing, it contains only +;; non-secret data. If present, the printed representation of the +;; encrypted data includes the delimiting double quotes. +;; +;; The plstore API (`plstore-open', `plstore-put', etc.) and the +;; plstore mode implemented by `plstore-mode' are orthogonal to each +;; other and should not be mixed up. In particular, encoding and +;; decoding a plstore mode buffer with `plstore-mode-toggle-display' +;; is not related in any way to the state of the plstore buffer. ;;; Code: @@ -457,6 +571,21 @@ If no one is selected, symmetric encryption will be performed. " (plstore--insert-buffer plstore) (save-buffer))) +;; The functions related to plstore mode unfortunately introduce yet +;; another alist format ("decoded alist"). After executing the "foo", +;; "bar", "baz" example from above the decoded alist of the plstore +;; would look like the following: +;; +;; (("foo" :host "foo.example.org" :port 80) +;; ("bar" :secret-user "test" :host "bar.example.org") +;; ("baz" :secret-password "test" :host "baz.example.org")) +;; +;; Even more unfortunately, variable and function names of the +;; following are a bit mixed up IMHO: With the current names, the +;; result of function `plstore--encode' is used to create what is +;; presented as "decoded form of a plstore" to the user. And variable +;; `plstore-encoded' is non-nil if a buffer shows the decoded form. + (defun plstore--encode (plstore) (plstore--decrypt plstore) (let ((merged-alist (plstore--get-merged-alist plstore))) From 2e20e318da23ce74ac6f736b557e10aa402c5cf9 Mon Sep 17 00:00:00 2001 From: Jens Schmidt Date: Mon, 22 May 2023 21:47:13 +0200 Subject: [PATCH 08/23] Brush up doc strings and terminology in plstore.el * lisp/plstore.el (plstore-encoded, plstore-passphrase-callback-function) (plstore--init-from-buffer, plstore-revert, plstore-close) (plstore--merge-secret, plstore--decrypt, plstore--match, plstore-find) (plstore-get, plstore-put, plstore-delete, plstore--insert-buffer) (plstore-save, plstore--encode, plstore--decode) (plstore--write-contents-functions, plstore-mode-decoded) (plstore-mode): Brush up doc strings and documentation in general. Fix terminology, in particular spurious occurences of all uppercase "PLSTORE". (Bug#63627) --- lisp/plstore.el | 70 ++++++++++++++++++++++++++++++++++++------------- 1 file changed, 52 insertions(+), 18 deletions(-) diff --git a/lisp/plstore.el b/lisp/plstore.el index 1a0dacffb01..d18d461d7d1 100644 --- a/lisp/plstore.el +++ b/lisp/plstore.el @@ -78,7 +78,7 @@ ;; Editing: ;; ;; This file also provides `plstore-mode', a major mode for editing -;; the PLSTORE format file. Visit a non-existing file and put the +;; the plstore format file. Visit a non-existing file and put the ;; following line: ;; ;; (("foo" :host "foo.example.org" :secret-user "user")) @@ -235,10 +235,13 @@ symmetric encryption will be used." (put 'plstore-encrypt-to 'permanent-local t) -(defvar plstore-encoded nil) +(defvar plstore-encoded nil + "Non-nil if the current buffer shows the decoded alist.") ; [sic!] (put 'plstore-encoded 'permanent-local t) +;;; EasyPG callback functions. + (defvar plstore-cache-passphrase-for-symmetric-encryption nil) (defvar plstore-passphrase-alist nil) @@ -255,11 +258,11 @@ symmetric encryption will be used." (cons entry plstore-passphrase-alist))) (setq passphrase - (read-passwd (format "Passphrase for PLSTORE %s: " + (read-passwd (format "Passphrase for plstore %s: " (plstore--get-buffer plstore)))) (setcdr entry (copy-sequence passphrase)) passphrase))) - (read-passwd (format "Passphrase for PLSTORE %s: " + (read-passwd (format "Passphrase for plstore %s: " (plstore--get-buffer plstore))))) (defun plstore-progress-callback-function (_context _what _char current total @@ -269,6 +272,8 @@ symmetric encryption will be used." (message "%s...%d%%" handback (if (> total 0) (floor (* (/ current (float total)) 100)) 0)))) +;;; Core functions. + (defun plstore--get-buffer (arg) (aref arg 0)) @@ -307,6 +312,7 @@ symmetric encryption will be used." (vector buffer alist encrypted-data secret-alist merged-alist)) (defun plstore--init-from-buffer (plstore) + "Parse current buffer and initialize PLSTORE from it." (goto-char (point-min)) (when (looking-at ";;; public entries") (forward-line) @@ -337,16 +343,20 @@ symmetric encryption will be used." store))) (defun plstore-revert (plstore) - "Replace current data in PLSTORE with the file on disk." + "Replace current data in PLSTORE from its associated file." (with-current-buffer (plstore--get-buffer plstore) (revert-buffer t t) (plstore--init-from-buffer plstore))) (defun plstore-close (plstore) - "Destroy a plstore instance PLSTORE." + "Destroy plstore instance PLSTORE." (kill-buffer (plstore--get-buffer plstore))) (defun plstore--merge-secret (plstore) + "Determine the merged alist of PLSTORE. +Create the merged alist as a copy of the template alist with all +placeholder properties that have corresponding properties in the +secret alist replaced by their plain-text secret properties." (let ((alist (plstore--get-secret-alist plstore)) modified-alist modified-plist @@ -365,19 +375,26 @@ symmetric encryption will be used." modified-entry (assoc (car entry) modified-alist) modified-plist (cdr modified-entry)) (while plist + ;; Search for a placeholder property in the merged alist + ;; corresponding to the current secret property. (setq placeholder (plist-member modified-plist (intern (concat ":secret-" (substring (symbol-name (car plist)) 1))))) + ;; Replace its name with the real, secret property name. (if placeholder (setcar placeholder (car plist))) + ;; Update its value to the plain-text secret property value. (setq modified-plist (plist-put modified-plist (car plist) (car (cdr plist)))) (setq plist (nthcdr 2 plist))) (setcdr modified-entry modified-plist)))) (defun plstore--decrypt (plstore) + "Decrypt the encrypted data of PLSTORE. +Update its internal alists and other data structures +accordingly." (if (plstore--get-encrypted-data plstore) (let ((context (epg-make-context 'OpenPGP)) plain) @@ -404,6 +421,11 @@ symmetric encryption will be used." (plstore--set-encrypted-data plstore nil)))) (defun plstore--match (entry keys skip-if-secret-found) + "Return whether plist KEYS matches ENTRY. +ENTRY should be a key of the merged alist of a PLSTORE. This +function returns nil if KEYS do not match ENTRY, t if they match, +and symbol `secret' if the secret alist needs to be consulted to +perform a match." (let ((result t) key-name key-value prop-value secret-name) (while keys (setq key-name (car keys) @@ -425,11 +447,10 @@ symmetric encryption will be used." result)) (defun plstore-find (plstore keys) - "Perform search on PLSTORE with KEYS. -KEYS is a plist." + "Return all PLSTORE entries matching plist KEYS." (let (entries alist entry match decrypt plist) - ;; First, go through the merged plist alist and collect entries - ;; matched with keys. + ;; First, go through the merged alist and collect entries matched + ;; by the keys. (setq alist (plstore--get-merged-alist plstore)) (while alist (setq entry (car alist) @@ -445,7 +466,7 @@ KEYS is a plist." plist nil)) (setq plist (nthcdr 2 plist))) (setq entries (cons entry entries))))) - ;; Second, decrypt the encrypted plist and try again. + ;; Second, decrypt the plstore and try again. (when decrypt (setq entries nil) (plstore--decrypt plstore) @@ -459,7 +480,8 @@ KEYS is a plist." (nreverse entries))) (defun plstore-get (plstore name) - "Get an entry with NAME in PLSTORE." + "Return the entry named NAME in PLSTORE. +Return nil if there is none." (let ((entry (assoc name (plstore--get-merged-alist plstore))) plist) (setq plist (cdr entry)) @@ -473,7 +495,7 @@ KEYS is a plist." entry)) (defun plstore-put (plstore name keys secret-keys) - "Put an entry with NAME in PLSTORE. + "Put an entry named NAME in PLSTORE. KEYS is a plist containing non-secret data. SECRET-KEYS is a plist containing secret data." (let (entry @@ -512,7 +534,7 @@ SECRET-KEYS is a plist containing secret data." (plstore--merge-secret plstore))) (defun plstore-delete (plstore name) - "Delete an entry with NAME from PLSTORE." + "Delete the first entry named NAME from PLSTORE." (let ((entry (assoc name (plstore--get-alist plstore)))) (if entry (plstore--set-alist @@ -531,6 +553,8 @@ SECRET-KEYS is a plist containing secret data." (defvar pp-escape-newlines) (defun plstore--insert-buffer (plstore) + "Insert the file representation of PLSTORE at point. +Assumes that PLSTORE has been decrypted." (insert ";;; public entries -*- mode: plstore -*- \n" (pp-to-string (plstore--get-alist plstore))) (if (plstore--get-secret-alist plstore) @@ -565,12 +589,14 @@ If no one is selected, symmetric encryption will be performed. " (insert ";;; secret entries\n" (pp-to-string cipher))))) (defun plstore-save (plstore) - "Save the contents of PLSTORE associated with a FILE." + "Save PLSTORE to its associated file." (with-current-buffer (plstore--get-buffer plstore) (erase-buffer) (plstore--insert-buffer plstore) (save-buffer))) +;;; plstore mode. + ;; The functions related to plstore mode unfortunately introduce yet ;; another alist format ("decoded alist"). After executing the "foo", ;; "bar", "baz" example from above the decoded alist of the plstore @@ -587,6 +613,7 @@ If no one is selected, symmetric encryption will be performed. " ;; `plstore-encoded' is non-nil if a buffer shows the decoded form. (defun plstore--encode (plstore) + "Return the printed representation of the decoded alist of PLSTORE." (plstore--decrypt plstore) (let ((merged-alist (plstore--get-merged-alist plstore))) (concat "(" @@ -611,6 +638,9 @@ If no one is selected, symmetric encryption will be performed. " ")"))) (defun plstore--decode (string) + "Create a plstore instance from STRING. +STRING should be the printed representation of a decoded alist of +some plstore." (let* ((alist (car (read-from-string string))) (pointer alist) secret-alist @@ -618,7 +648,7 @@ If no one is selected, symmetric encryption will be performed. " entry) (while pointer (unless (stringp (car (car pointer))) - (error "Invalid PLSTORE format %s" string)) + (error "Invalid plstore format %s" string)) (setq plist (cdr (car pointer))) (while plist (when (string-match "\\`:secret-" (symbol-name (car plist))) @@ -638,6 +668,10 @@ If no one is selected, symmetric encryption will be performed. " (plstore--make nil alist nil secret-alist))) (defun plstore--write-contents-functions () + "Convert the decoded form of a plstore in the current buffer. +Convert it to the regular file representation of a plstore if +needed. This function is used on hook `write-contents-functions' +in plstore mode buffers." (when plstore-encoded (let ((store (plstore--decode (buffer-string))) (file (buffer-file-name))) @@ -675,7 +709,7 @@ If no one is selected, symmetric encryption will be performed. " (erase-buffer) (insert (substitute-command-keys "\ -;;; You are looking at the decoded form of the PLSTORE file.\n\ +;;; You are looking at the decoded form of the plstore file.\n\ ;;; To see the original form content, do \\[plstore-mode-toggle-display]\n\n")) (insert (plstore--encode store)) (set-buffer-modified-p nil) @@ -690,7 +724,7 @@ If no one is selected, symmetric encryption will be performed. " ;;;###autoload (define-derived-mode plstore-mode emacs-lisp-mode "PLSTORE" - "Major mode for editing PLSTORE files." + "Major mode for editing plstore files." (make-local-variable 'plstore-encoded) (add-hook 'write-contents-functions #'plstore--write-contents-functions) (define-key plstore-mode-map "\C-c\C-c" #'plstore-mode-toggle-display) From ed4cd3eddf7763a70630df8fd238592e6f3b881c Mon Sep 17 00:00:00 2001 From: Randy Taylor Date: Sat, 27 May 2023 20:52:37 -0400 Subject: [PATCH 09/23] dockerfile-ts-mode: Prevent empty categories in imenu (Bug#63759) * lisp/progmodes/dockerfile-ts-mode.el (dockerfile-ts-mode--imenu): Don't include empty categories. --- lisp/progmodes/dockerfile-ts-mode.el | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lisp/progmodes/dockerfile-ts-mode.el b/lisp/progmodes/dockerfile-ts-mode.el index f2f30cf2617..2973b5149db 100644 --- a/lisp/progmodes/dockerfile-ts-mode.el +++ b/lisp/progmodes/dockerfile-ts-mode.el @@ -123,8 +123,9 @@ continuation to the previous entry." (let* ((node (treesit-buffer-root-node)) (stage-tree (treesit-induce-sparse-tree node "from_instruction" - nil 1000))) - `(("Stage" . ,(dockerfile-ts-mode--imenu-1 stage-tree))))) + nil 1000)) + (stage-index (dockerfile-ts-mode--imenu-1 stage-tree))) + (when stage-index `(("Stage" . ,stage-index))))) (defun dockerfile-ts-mode--imenu-1 (node) "Helper for `dockerfile-ts-mode--imenu'. From 83b22139e4c2cf5ffb9544dd910319528ed7ebc8 Mon Sep 17 00:00:00 2001 From: Stephen Berman Date: Wed, 31 May 2023 16:15:48 +0200 Subject: [PATCH 10/23] Fix several todo-mode.el item editing bugs (bug#63811) * lisp/calendar/todo-mode.el (todo-insert-item--basic): With insertion type 'here', ensure item is inserted on the todo-mode line where the command was invoked. (todo-edit-item--cat, todo-edit-item--pos): New variables. (todo-edit-item--text): Restrict the scope of nil-valued buffer-read-only to the functions that change buffer text. If user moved point while editing a single-line todo item or a done item comment, or while inserting a done item comment, restore point, and for comments, make sure the done items section is displayed. For multiline items, set the new variables so todo-edit-quit can use them. (todo-edit-quit): Use the values of the new variables to restore point in the todo-mode buffer if it had been moved while editing. (todo-edit-item--header): Avoid clobbering match data when editing a todo item header. --- lisp/calendar/todo-mode.el | 298 +++++++++++++++++++++---------------- 1 file changed, 168 insertions(+), 130 deletions(-) diff --git a/lisp/calendar/todo-mode.el b/lisp/calendar/todo-mode.el index 671210f3ee8..35cac5d7310 100644 --- a/lisp/calendar/todo-mode.el +++ b/lisp/calendar/todo-mode.el @@ -1985,7 +1985,13 @@ their associated keys and their effects." (setq done-only t) (todo-toggle-view-done-only)) (if here - (todo-insert-with-overlays new-item) + (progn + ;; Ensure item is inserted where command was invoked. + (unless (= (point) opoint) + (todo-category-number ocat) + (todo-category-select) + (goto-char opoint)) + (todo-insert-with-overlays new-item)) (todo-set-item-priority new-item cat t)) (setq item-added t)) ;; If user cancels before setting priority, restore @@ -2119,6 +2125,9 @@ the item at point." ((or marked (todo-item-string)) (todo-edit-item--next-key 'todo arg))))) +(defvar todo-edit-item--cat nil) +(defvar todo-edit-item--pos nil) + (defun todo-edit-item--text (&optional arg) "Function providing the text editing facilities of `todo-edit-item'." (let ((full-item (todo-item-string))) @@ -2127,6 +2136,7 @@ the item at point." ;; 1+ signals an error, so just make this a noop. (when full-item (let* ((opoint (point)) + (ocat (todo-current-category)) (start (todo-item-start)) (end (save-excursion (todo-item-end))) (item-beg (progn @@ -2151,8 +2161,7 @@ the item at point." (concat " \\[" (regexp-quote todo-comment-string) ": \\([^]]+\\)\\]") end t))) - (prompt (if comment "Edit comment: " "Enter a comment: ")) - (buffer-read-only nil)) + (prompt (if comment "Edit comment: " "Enter a comment: "))) ;; When there are marked items, user can invoke todo-edit-item ;; even if point is not on an item, but text editing only ;; applies to the item at point. @@ -2170,22 +2179,43 @@ the item at point." end t) (if comment-delete (when (todo-y-or-n-p "Delete comment? ") - (delete-region (match-beginning 0) (match-end 0))) - (replace-match (save-match-data - (read-string prompt - (cons (match-string 1) 1))) - nil nil nil 1)) + (let ((buffer-read-only nil)) + (delete-region (match-beginning 0) (match-end 0)))) + (let ((buffer-read-only nil)) + (replace-match (save-match-data + (prog1 (let ((buffer-read-only t)) + (read-string + prompt + (cons (match-string 1) 1))) + ;; If user moved point while editing + ;; a comment, restore it and ensure + ;; done items section is displayed. + (unless (= (point) opoint) + (todo-category-number ocat) + (let ((todo-show-with-done t)) + (todo-category-select) + (goto-char opoint))))) + nil nil nil 1))) (if comment-delete (user-error "There is no comment to delete") - (insert " [" todo-comment-string ": " - (prog1 (read-string prompt) - ;; If user moved point during editing, - ;; make sure it moves back. - (goto-char opoint) - (todo-item-end)) - "]"))))) + (let ((buffer-read-only nil)) + (insert " [" todo-comment-string ": " + (prog1 (let ((buffer-read-only t)) + (read-string prompt)) + ;; If user moved point while inserting a + ;; comment, restore it and ensure done items + ;; section is displayed. + (unless (= (point) opoint) + (todo-category-number ocat) + (let ((todo-show-with-done t)) + (todo-category-select) + (goto-char opoint))) + (todo-item-end)) + "]")))))) (multiline (let ((buf todo-edit-buffer)) + (setq todo-edit-item--cat ocat) + (setq todo-edit-item--pos opoint) (set-window-buffer (selected-window) (set-buffer (make-indirect-buffer (buffer-name) buf))) @@ -2208,10 +2238,14 @@ the item at point." ;; Ensure lines following hard newlines are indented. (setq new (replace-regexp-in-string "\\(\n\\)[^[:blank:]]" "\n\t" new nil nil 1)) - ;; If user moved point during editing, make sure it moves back. - (goto-char opoint) - (todo-remove-item) - (todo-insert-with-overlays new) + ;; If user moved point while editing item, restore it. + (unless (= (point) opoint) + (todo-category-number ocat) + (todo-category-select) + (goto-char opoint)) + (let ((buffer-read-only nil)) + (todo-remove-item) + (todo-insert-with-overlays new)) (move-to-column item-beg))))))))) (defun todo-edit-quit () @@ -2243,6 +2277,9 @@ made in the number or names of categories." (kill-buffer) (unless (eq (current-buffer) buf) (set-window-buffer (selected-window) (set-buffer buf))) + (todo-category-number todo-edit-item--cat) + (todo-category-select) + (goto-char todo-edit-item--pos) (if transient-mark-mode (deactivate-mark))) ;; We got here via `F e'. (when (todo-check-format) @@ -2315,117 +2352,118 @@ made in the number or names of categories." ;; If there are marked items, use only the first to set ;; header changes, and apply these to all marked items. (when first - (cond - ((eq what 'date) - (setq ndate (todo-read-date))) - ((eq what 'calendar) - (setq ndate (save-match-data (todo-set-date-from-calendar)))) - ((eq what 'today) - (setq ndate (calendar-date-string (calendar-current-date) t t))) - ((eq what 'dayname) - (setq ndate (todo-read-dayname))) - ((eq what 'time) - (setq ntime (save-match-data (todo-read-time))) - (when (> (length ntime) 0) - (setq ntime (concat " " ntime)))) - ;; When date string consists only of a day name, - ;; passing other date components is a noop. - ((and odayname (memq what '(year month day)))) - ((eq what 'year) - (setq day oday - monthname omonthname - month omonth - year (cond ((not current-prefix-arg) - (todo-read-date 'year)) - ((string= oyear "*") - (user-error "Cannot increment *")) - (t - (number-to-string (+ yy inc)))))) - ((eq what 'month) - (setf day oday - year oyear - (if (memq 'month calendar-date-display-form) - month - monthname) - (cond ((not current-prefix-arg) - (todo-read-date 'month)) - ((or (string= omonth "*") (= mm 13)) - (user-error "Cannot increment *")) - (t - (let* ((mmo mm) - ;; Change by 12 or more months? - (bigincp (>= (abs inc) 12)) - ;; Month number is in range 1..12. - (mminc (+ mm (% inc 12))) - (mm (% (+ mminc 12) 12)) - ;; 12n mod 12 = 0, so 0 is December. - (mm (if (= mm 0) 12 mm)) - ;; Does change in month cross year? - (mmcmp (cond ((< inc 0) (> mm mmo)) - ((> inc 0) (< mm mmo)))) - (yyadjust (if bigincp - (+ (abs (/ inc 12)) - (if mmcmp 1 0)) - 1))) - ;; Adjust year if necessary. - (setq yy (cond ((and (< inc 0) - (or mmcmp bigincp)) - (- yy yyadjust)) - ((and (> inc 0) - (or mmcmp bigincp)) - (+ yy yyadjust)) - (t yy))) - (setq year (number-to-string yy)) - ;; Return the changed numerical month as - ;; a string or the corresponding month name. - (if omonth - (number-to-string mm) - (aref tma-array (1- mm))))))) - ;; Since the number corresponding to the arbitrary - ;; month name "*" is out of the range of - ;; calendar-last-day-of-month, set it to 1 - ;; (corresponding to January) to allow 31 days. - (let ((mm (if (= mm 13) 1 mm))) - (if (> (string-to-number day) - (calendar-last-day-of-month mm yy)) - (user-error "%s %s does not have %s days" - (aref tmn-array (1- mm)) - (if (= mm 2) yy "") day)))) - ((eq what 'day) - (setq year oyear - month omonth - monthname omonthname - day (cond - ((not current-prefix-arg) - (todo-read-date 'day mm yy)) - ((string= oday "*") - (user-error "Cannot increment *")) - ((or (string= omonth "*") (string= omonthname "*")) - (setq dd (+ dd inc)) - (if (> dd 31) - (user-error - "A month cannot have more than 31 days") - (number-to-string dd))) - ;; Increment or decrement day by INC, - ;; adjusting month and year if necessary - ;; (if year is "*" assume current year to - ;; calculate adjustment). - (t - (let* ((yy (or yy (calendar-extract-year - (calendar-current-date)))) - (date (calendar-gregorian-from-absolute - (+ (calendar-absolute-from-gregorian - (list mm dd yy)) - inc))) - (adjmm (nth 0 date))) - ;; Set year and month(name) to adjusted values. - (unless (string= year "*") - (setq year (number-to-string (nth 2 date)))) - (if month - (setq month (number-to-string adjmm)) - (setq monthname (aref tma-array (1- adjmm)))) - ;; Return changed numerical day as a string. - (number-to-string (nth 1 date))))))))) + (save-match-data + (cond + ((eq what 'date) + (setq ndate (todo-read-date))) + ((eq what 'calendar) + (setq ndate (todo-set-date-from-calendar))) + ((eq what 'today) + (setq ndate (calendar-date-string (calendar-current-date) t t))) + ((eq what 'dayname) + (setq ndate (todo-read-dayname))) + ((eq what 'time) + (setq ntime (todo-read-time)) + (when (> (length ntime) 0) + (setq ntime (concat " " ntime)))) + ;; When date string consists only of a day name, + ;; passing other date components is a noop. + ((and odayname (memq what '(year month day)))) + ((eq what 'year) + (setq day oday + monthname omonthname + month omonth + year (cond ((not current-prefix-arg) + (todo-read-date 'year)) + ((string= oyear "*") + (user-error "Cannot increment *")) + (t + (number-to-string (+ yy inc)))))) + ((eq what 'month) + (setf day oday + year oyear + (if (memq 'month calendar-date-display-form) + month + monthname) + (cond ((not current-prefix-arg) + (todo-read-date 'month)) + ((or (string= omonth "*") (= mm 13)) + (user-error "Cannot increment *")) + (t + (let* ((mmo mm) + ;; Change by 12 or more months? + (bigincp (>= (abs inc) 12)) + ;; Month number is in range 1..12. + (mminc (+ mm (% inc 12))) + (mm (% (+ mminc 12) 12)) + ;; 12n mod 12 = 0, so 0 is December. + (mm (if (= mm 0) 12 mm)) + ;; Does change in month cross year? + (mmcmp (cond ((< inc 0) (> mm mmo)) + ((> inc 0) (< mm mmo)))) + (yyadjust (if bigincp + (+ (abs (/ inc 12)) + (if mmcmp 1 0)) + 1))) + ;; Adjust year if necessary. + (setq yy (cond ((and (< inc 0) + (or mmcmp bigincp)) + (- yy yyadjust)) + ((and (> inc 0) + (or mmcmp bigincp)) + (+ yy yyadjust)) + (t yy))) + (setq year (number-to-string yy)) + ;; Return the changed numerical month as + ;; a string or the corresponding month name. + (if omonth + (number-to-string mm) + (aref tma-array (1- mm))))))) + ;; Since the number corresponding to the arbitrary + ;; month name "*" is out of the range of + ;; calendar-last-day-of-month, set it to 1 + ;; (corresponding to January) to allow 31 days. + (let ((mm (if (= mm 13) 1 mm))) + (if (> (string-to-number day) + (calendar-last-day-of-month mm yy)) + (user-error "%s %s does not have %s days" + (aref tmn-array (1- mm)) + (if (= mm 2) yy "") day)))) + ((eq what 'day) + (setq year oyear + month omonth + monthname omonthname + day (cond + ((not current-prefix-arg) + (todo-read-date 'day mm yy)) + ((string= oday "*") + (user-error "Cannot increment *")) + ((or (string= omonth "*") (string= omonthname "*")) + (setq dd (+ dd inc)) + (if (> dd 31) + (user-error + "A month cannot have more than 31 days") + (number-to-string dd))) + ;; Increment or decrement day by INC, + ;; adjusting month and year if necessary + ;; (if year is "*" assume current year to + ;; calculate adjustment). + (t + (let* ((yy (or yy (calendar-extract-year + (calendar-current-date)))) + (date (calendar-gregorian-from-absolute + (+ (calendar-absolute-from-gregorian + (list mm dd yy)) + inc))) + (adjmm (nth 0 date))) + ;; Set year and month(name) to adjusted values. + (unless (string= year "*") + (setq year (number-to-string (nth 2 date)))) + (if month + (setq month (number-to-string adjmm)) + (setq monthname (aref tma-array (1- adjmm)))) + ;; Return changed numerical day as a string. + (number-to-string (nth 1 date)))))))))) (unless odayname ;; If year, month or day date string components were ;; changed, rebuild the date string. From 0a354d65784e5cd25da408c4b102fb1c15fa7a73 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Wed, 31 May 2023 17:50:53 +0300 Subject: [PATCH 11/23] Fix infloop in info-look.el * lisp/info-look.el (info-lookup-guess-gdb-script-symbol): Fix infloop when there are no completions. (Bug#63808) --- lisp/info-look.el | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lisp/info-look.el b/lisp/info-look.el index 7858ed58774..da45e30cd36 100644 --- a/lisp/info-look.el +++ b/lisp/info-look.el @@ -733,7 +733,11 @@ Return nil if there is nothing appropriate in the buffer near point." (let ((str (string-join str-list " "))) (when (assoc str completions) (throw 'result str)) - (nbutlast str-list))))))) + ;; 'nbutlast' will not destructively set its argument + ;; to nil when the argument is a list of 1 element. + (if (= (length str-list) 1) + (setq str-list nil) + (nbutlast str-list)))))))) (error nil))) ;;;###autoload From e252ce26eab1e135ed294171b249d6560474bfd1 Mon Sep 17 00:00:00 2001 From: Theodor Thornhill Date: Wed, 31 May 2023 20:47:06 +0200 Subject: [PATCH 12/23] Add type_predicate 'is' as keyword in typescript-ts-mode (bug#63810) * lisp/progmodes/typescript-ts-mode.el (typescript-ts-mode--keywords): New keyword 'is'. --- lisp/progmodes/typescript-ts-mode.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lisp/progmodes/typescript-ts-mode.el b/lisp/progmodes/typescript-ts-mode.el index 11f20add3ee..e30eb880266 100644 --- a/lisp/progmodes/typescript-ts-mode.el +++ b/lisp/progmodes/typescript-ts-mode.el @@ -128,7 +128,7 @@ Argument LANGUAGE is either `typescript' or `tsx'." "case" "catch" "class" "const" "continue" "debugger" "declare" "default" "delete" "do" "else" "enum" "export" "extends" "finally" "for" "from" "function" - "get" "if" "implements" "import" "in" "instanceof" "interface" + "get" "if" "implements" "import" "in" "instanceof" "interface" "is" "keyof" "let" "namespace" "new" "of" "private" "protected" "public" "readonly" "return" "set" "static" "switch" "target" "throw" "try" "type" "typeof" "var" "void" From 17c7915ab947ebeec6ea5ad3eb4cad1f24d5d4fc Mon Sep 17 00:00:00 2001 From: Philip Kaludercic Date: Sat, 27 May 2023 10:13:21 +0200 Subject: [PATCH 13/23] ; Fix 'package-install-upgrade-built-in' check for package menu * lisp/emacs-lisp/package.el (package-menu--find-upgrades): Use correct check to verify if a built-in packages in the package menu can be upgraded or not. This change improves upon a faulty assumption from ba2c76fa2bc3aabfda7d1d09cc5148f3f9d8e08e. (Bug#63587) --- lisp/emacs-lisp/package.el | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lisp/emacs-lisp/package.el b/lisp/emacs-lisp/package.el index 202aca36f24..8f266186d5e 100644 --- a/lisp/emacs-lisp/package.el +++ b/lisp/emacs-lisp/package.el @@ -3769,8 +3769,8 @@ object corresponding to the newer version." (and avail-pkg (version-list-< (package-desc-priority-version pkg-desc) (package-desc-priority-version avail-pkg)) - (xor (not package-install-upgrade-built-in) - (package--active-built-in-p pkg-desc)) + (or (not (package--active-built-in-p pkg-desc)) + package-install-upgrade-built-in) (push (cons name avail-pkg) upgrades)))) upgrades)) From 753f8aa1f14c2ff5d86b086230d600eb9bb5d8bc Mon Sep 17 00:00:00 2001 From: Dmitry Gutov Date: Fri, 2 Jun 2023 05:10:15 +0300 Subject: [PATCH 14/23] Fix project-name for vc-aware backend in non-file buffers * lisp/progmodes/project.el (project-name): Make sure project-vc-name is picked up from dir-locals in all non-file-visiting buffers too (mentioned in bug#63469). --- lisp/progmodes/project.el | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lisp/progmodes/project.el b/lisp/progmodes/project.el index 617ca45ed0d..d482cc24d70 100644 --- a/lisp/progmodes/project.el +++ b/lisp/progmodes/project.el @@ -805,8 +805,8 @@ DIRS must contain directory names." (push buf bufs))) (nreverse bufs))) -(cl-defmethod project-name ((_project (head vc))) - (or project-vc-name +(cl-defmethod project-name ((project (head vc))) + (or (project--value-in-dir 'project-vc-name (project-root project)) (cl-call-next-method))) From 2f94f6de9d64f9fd89284dac171e166e7d721dcd Mon Sep 17 00:00:00 2001 From: Robert Pluim Date: Fri, 2 Jun 2023 13:54:56 +0200 Subject: [PATCH 15/23] Make VS-15 and VS-16 compositions work correctly There is a conflict between forward matching and backward matching composition rules involving the same codepoint, which can cause the backward matching ones not to be invoked. Ensure that VS-15 (U+FE0E) and VS-16 (U+FE0F) are composed by forward matching rules instead in order to avoid this issue. * admin/unidata/emoji-zwj.awk: Add rules for CHAR+VS-15 and CHAR+VS-16. * lisp/composite.el: remove backward matching rule for VS-15. (Bug#63731) --- admin/unidata/emoji-zwj.awk | 3 ++- lisp/composite.el | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/admin/unidata/emoji-zwj.awk b/admin/unidata/emoji-zwj.awk index 7d2ff6cb900..f13f796bcac 100644 --- a/admin/unidata/emoji-zwj.awk +++ b/admin/unidata/emoji-zwj.awk @@ -106,7 +106,8 @@ END { for (elt in ch) { - printf("(#x%s .\n,(eval-when-compile (regexp-opt\n'(\n%s\n))))\n", elt, vec[elt]) + entries = sprintf("%s\n\"\\N{U+%s}\\N{U+FE0E}\"\n\"\\N{U+%s}\\N{U+FE0F}\"", vec[elt], elt, elt) + printf("(#x%s .\n,(eval-when-compile (regexp-opt\n'(\n%s\n))))\n", elt, entries) } print "))" print " (set-char-table-range composition-function-table" diff --git a/lisp/composite.el b/lisp/composite.el index fb8b76114f4..9710c3c371b 100644 --- a/lisp/composite.el +++ b/lisp/composite.el @@ -861,7 +861,7 @@ and the second is a glyph for a variation selector." ;; handled in font_range, we end up choosing the Emoji presentation ;; rather than the Text presentation. (let ((elt '([".." 1 compose-gstring-for-variation-glyph]))) - (set-char-table-range composition-function-table '(#xFE00 . #xFE0E) elt) + (set-char-table-range composition-function-table '(#xFE00 . #xFE0D) elt) (set-char-table-range composition-function-table '(#xE0100 . #xE01EF) elt)) (defun auto-compose-chars (func from to font-object string direction) From dc7acb1aafe9b0b84481ac51a5bd5125d263537e Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Fri, 2 Jun 2023 15:42:42 +0300 Subject: [PATCH 16/23] Avoid errors in 'delete-forward-char' deleting static compositions * lisp/simple.el (delete-forward-char): Fix recognition of static compositions. (Bug#63837) --- lisp/simple.el | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lisp/simple.el b/lisp/simple.el index 3f88fcb8d03..9df5958a168 100644 --- a/lisp/simple.el +++ b/lisp/simple.el @@ -1520,7 +1520,8 @@ the actual saved text might be different from what was killed." (let ((from (car cmp)) (to (cadr cmp))) (cond - ((= (length cmp) 2) ; static composition + ((and (= (length cmp) 3) ; static composition + (booleanp (nth 2 cmp))) to) ;; TO can be at POS, in which case we want ;; to make sure we advance at least by 1 From 03663b8798a06bf18ff1e235ac0fb87870f8fe77 Mon Sep 17 00:00:00 2001 From: Jonas Bernoulli Date: Fri, 2 Jun 2023 23:26:45 +0200 Subject: [PATCH 17/23] Update to Transient v0.4.1 --- doc/misc/transient.texi | 6 +++--- lisp/transient.el | 19 +++++++++++++------ 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/doc/misc/transient.texi b/doc/misc/transient.texi index 330fdd1e3a2..be9e8698ab4 100644 --- a/doc/misc/transient.texi +++ b/doc/misc/transient.texi @@ -31,7 +31,7 @@ General Public License for more details. @finalout @titlepage @title Transient User and Developer Manual -@subtitle for version 0.4.0 +@subtitle for version 0.4.1 @author Jonas Bernoulli @page @vskip 0pt plus 1filll @@ -74,7 +74,7 @@ that hurdle is Psionic K's interactive tutorial, available at @end quotation @noindent -This manual is for Transient version 0.4.0. +This manual is for Transient version 0.4.1. @insertcopying @end ifnottex @@ -2150,7 +2150,7 @@ default value of a prefix using the same format as returned by @item @code{always-read} For options, whether to read a value on every invocation. -If this is nil, then options that have a value are simply unset and +If this is @code{nil}, then options that have a value are simply unset and have to be invoked a second time to set a new value. @item diff --git a/lisp/transient.el b/lisp/transient.el index 1d763c4ddeb..048554eee13 100644 --- a/lisp/transient.el +++ b/lisp/transient.el @@ -6,7 +6,7 @@ ;; URL: https://github.com/magit/transient ;; Keywords: extensions -;; Package-Version: 0.4.0 +;; Package-Version: 0.4.1 ;; Package-Requires: ((emacs "26.1")) ;; SPDX-License-Identifier: GPL-3.0-or-later @@ -1643,6 +1643,7 @@ of the corresponding object." "" #'transient--do-stay "" #'transient--do-stay "" #'transient--do-stay + "" #'transient--do-stay "" #'transient--do-minus "" #'transient--do-stay "" #'transient--do-quit-all @@ -3043,10 +3044,12 @@ prompt." (progn (cl-call-next-method obj value) (dolist (arg incomp) - (when-let ((obj (cl-find-if (lambda (obj) - (and (slot-boundp obj 'argument) - (equal (oref obj argument) arg))) - transient--suffixes))) + (when-let ((obj (cl-find-if + (lambda (obj) + (and (slot-exists-p obj 'argument) + (slot-boundp obj 'argument) + (equal (oref obj argument) arg))) + transient--suffixes))) (let ((transient--unset-incompatible nil)) (transient-infix-set obj nil))))) (cl-call-next-method obj value)))) @@ -3253,6 +3256,8 @@ have a history of their own.") (with-current-buffer buf (when transient-enable-popup-navigation (setq focus (or (button-get (point) 'command) + (and (not (bobp)) + (button-get (1- (point)) 'command)) (transient--heading-at-point)))) (erase-buffer) (setq window-size-fixed t) @@ -3384,7 +3389,9 @@ have a history of their own.") (insert ?\n) (insert (propertize " " 'display `(space :align-to (,(nth (1+ c) cc))))))) - (insert (make-string (max 1 (- (nth c cc) (current-column))) ?\s)) + (when (> c 0) + (insert (make-string (max 1 (- (nth c cc) (current-column))) + ?\s))) (when-let ((cell (nth r (nth c columns)))) (insert cell)) (when (= c (1- cs)) From 348e4504c6d5588443809ec28da3c3c693368e16 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Sat, 3 Jun 2023 09:14:44 +0300 Subject: [PATCH 18/23] Fix typo in calc.texi * doc/misc/calc.texi (Programming Tutorial): Fix a typo. Suggested by Vladimir Nikishkin . --- doc/misc/calc.texi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/misc/calc.texi b/doc/misc/calc.texi index 4b62eee56e2..3b525996d6f 100644 --- a/doc/misc/calc.texi +++ b/doc/misc/calc.texi @@ -6217,7 +6217,7 @@ method when it is able. @xref{Programming Answer 8, 8}. (@bullet{}) @cindex Gamma constant, Euler's @cindex Euler's gamma constant (@bullet{}) @strong{Exercise 9.} The @dfn{digamma} function -@texline @math{\psi(z) (``psi'')} +@texline @math{\psi(z)} (``psi'') @infoline @expr{psi(z)} is defined as the derivative of @texline @math{\ln \Gamma(z)}. From 6b2c8dc9050c5c0514fa404733ce1d4a37d00e39 Mon Sep 17 00:00:00 2001 From: kobarity Date: Fri, 2 Jun 2023 22:52:57 +0900 Subject: [PATCH 19/23] Revert "Enhance Python font-lock to support multilines" This reverts commit 4915ca5dd4245a909c046e6691e8d4a1919890c8. We have found that there are performance issues when editing a large file. The issue can be reproduced as follows: 1. emacs -Q 2. Open large Python file (e.g. turtle.py in Python) 3. Near the top of the buffer, enter open paren and some characters. The above commit extends the region to be font-locked using `python-nav-end-of-statement'. However, if there are unbalanced parens, it may move point to the end of the buffer. This causes almost the entire buffer to be font-locked, which is not acceptable for large files. --- lisp/progmodes/python.el | 49 +++------- test/lisp/progmodes/python-tests.el | 144 ---------------------------- 2 files changed, 15 insertions(+), 178 deletions(-) diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el index adaeacc2ec1..974e07c3c6a 100644 --- a/lisp/progmodes/python.el +++ b/lisp/progmodes/python.el @@ -415,7 +415,6 @@ instead." "Python mode specialized rx macro. This variant of `rx' supports common Python named REGEXPS." `(rx-let ((sp-bsnl (or space (and ?\\ ?\n))) - (sp-nl (or space (and (? ?\\) ?\n))) (block-start (seq symbol-start (or "def" "class" "if" "elif" "else" "try" "except" "finally" "for" "while" "with" @@ -650,9 +649,9 @@ the {...} holes that appear within f-strings." finally return (and result-valid result)))) (defvar python-font-lock-keywords-level-1 - `((,(python-rx symbol-start "def" (1+ sp-bsnl) (group symbol-name)) + `((,(python-rx symbol-start "def" (1+ space) (group symbol-name)) (1 font-lock-function-name-face)) - (,(python-rx symbol-start "class" (1+ sp-bsnl) (group symbol-name)) + (,(python-rx symbol-start "class" (1+ space) (group symbol-name)) (1 font-lock-type-face))) "Font lock keywords to use in `python-mode' for level 1 decoration. @@ -792,12 +791,12 @@ sign in chained assignment." ;; [*a] = 5, 6 ;; are handled separately below (,(python-font-lock-assignment-matcher - (python-rx (? (or "[" "(") (* sp-nl)) - grouped-assignment-target (* sp-nl) ?, (* sp-nl) - (* assignment-target (* sp-nl) ?, (* sp-nl)) - (? assignment-target (* sp-nl)) - (? ?, (* sp-nl)) - (? (or ")" "]") (* sp-bsnl)) + (python-rx (? (or "[" "(") (* space)) + grouped-assignment-target (* space) ?, (* space) + (* assignment-target (* space) ?, (* space)) + (? assignment-target (* space)) + (? ?, (* space)) + (? (or ")" "]") (* space)) (group assignment-operator))) (1 font-lock-variable-name-face) (2 'font-lock-operator-face) @@ -813,9 +812,9 @@ sign in chained assignment." ;; c: Collection = {1, 2, 3} ;; d: Mapping[int, str] = {1: 'bar', 2: 'baz'} (,(python-font-lock-assignment-matcher - (python-rx (or line-start ?\;) (* sp-bsnl) - grouped-assignment-target (* sp-bsnl) - (? ?: (* sp-bsnl) (+ not-simple-operator) (* sp-bsnl)) + (python-rx (or line-start ?\;) (* space) + grouped-assignment-target (* space) + (? ?: (* space) (+ not-simple-operator) (* space)) (group assignment-operator))) (1 font-lock-variable-name-face) (2 'font-lock-operator-face)) @@ -824,10 +823,10 @@ sign in chained assignment." ;; [a] = 5, ;; [*a] = 5, 6 (,(python-font-lock-assignment-matcher - (python-rx (or line-start ?\; ?=) (* sp-bsnl) - (or "[" "(") (* sp-nl) - grouped-assignment-target (* sp-nl) - (or ")" "]") (* sp-bsnl) + (python-rx (or line-start ?\; ?=) (* space) + (or "[" "(") (* space) + grouped-assignment-target (* space) + (or ")" "]") (* space) (group assignment-operator))) (1 font-lock-variable-name-face) (2 'font-lock-operator-face)) @@ -869,22 +868,6 @@ decorators, exceptions, and assignments.") Which one will be chosen depends on the value of `font-lock-maximum-decoration'.") -(defvar font-lock-beg) -(defvar font-lock-end) -(defun python-font-lock-extend-region () - "Extend font-lock region to statement boundaries." - (let ((beg font-lock-beg) - (end font-lock-end)) - (goto-char beg) - (python-nav-beginning-of-statement) - (beginning-of-line) - (when (< (point) beg) - (setq font-lock-beg (point))) - (goto-char end) - (python-nav-end-of-statement) - (when (< end (point)) - (setq font-lock-end (point))) - (or (/= beg font-lock-beg) (/= end font-lock-end)))) (defconst python-syntax-propertize-function (syntax-propertize-rules @@ -6709,8 +6692,6 @@ implementations: `python-mode' and `python-ts-mode'." nil nil nil nil (font-lock-syntactic-face-function . python-font-lock-syntactic-face-function))) - (add-hook 'font-lock-extend-region-functions - #'python-font-lock-extend-region nil t) (setq-local syntax-propertize-function python-syntax-propertize-function) (setq-local imenu-create-index-function diff --git a/test/lisp/progmodes/python-tests.el b/test/lisp/progmodes/python-tests.el index cbaf5b698bd..e1b4c0a74c0 100644 --- a/test/lisp/progmodes/python-tests.el +++ b/test/lisp/progmodes/python-tests.el @@ -136,20 +136,6 @@ STRING, it is skipped so the next STRING occurrence is selected." while pos collect (cons pos (get-text-property pos 'face)))) -(defun python-tests-assert-faces-after-change (content faces search replace) - "Assert that font faces for CONTENT are equal to FACES after change. -All occurrences of SEARCH are changed to REPLACE." - (python-tests-with-temp-buffer - content - ;; Force enable font-lock mode without jit-lock. - (rename-buffer "*python-font-lock-test*" t) - (let (noninteractive font-lock-support-mode) - (font-lock-mode)) - (while - (re-search-forward search nil t) - (replace-match replace)) - (should (equal faces (python-tests-get-buffer-faces))))) - (defun python-tests-self-insert (char-or-str) "Call `self-insert-command' for chars in CHAR-OR-STR." (let ((chars @@ -297,13 +283,6 @@ p = (1 + 2) "def 1func():" '((1 . font-lock-keyword-face) (4)))) -(ert-deftest python-font-lock-keywords-level-1-3 () - (python-tests-assert-faces - "def \\ - func():" - '((1 . font-lock-keyword-face) (4) - (15 . font-lock-function-name-face) (19)))) - (ert-deftest python-font-lock-assignment-statement-1 () (python-tests-assert-faces "a, b, c = 1, 2, 3" @@ -495,129 +474,6 @@ def f(x: CustomInt) -> CustomInt: (136 . font-lock-operator-face) (137) (144 . font-lock-keyword-face) (150)))) -(ert-deftest python-font-lock-assignment-statement-multiline-1 () - (python-tests-assert-faces-after-change - " -[ - a, - b -] # ( - 1, - 2 -) -" - '((1) - (8 . font-lock-variable-name-face) (9) - (15 . font-lock-variable-name-face) (16) - (19 . font-lock-operator-face) (20)) - "#" "=")) - -(ert-deftest python-font-lock-assignment-statement-multiline-2 () - (python-tests-assert-faces-after-change - " -[ - *a -] # 5, 6 -" - '((1) - (8 . font-lock-operator-face) - (9 . font-lock-variable-name-face) (10) - (13 . font-lock-operator-face) (14)) - "#" "=")) - -(ert-deftest python-font-lock-assignment-statement-multiline-3 () - (python-tests-assert-faces-after-change - "a\\ - ,\\ - b\\ - ,\\ - c\\ - #\\ - 1\\ - ,\\ - 2\\ - ,\\ - 3" - '((1 . font-lock-variable-name-face) (2) - (15 . font-lock-variable-name-face) (16) - (29 . font-lock-variable-name-face) (30) - (36 . font-lock-operator-face) (37)) - "#" "=")) - -(ert-deftest python-font-lock-assignment-statement-multiline-4 () - (python-tests-assert-faces-after-change - "a\\ - :\\ - int\\ - #\\ - 5" - '((1 . font-lock-variable-name-face) (2) - (15 . font-lock-builtin-face) (18) - (24 . font-lock-operator-face) (25)) - "#" "=")) - -(ert-deftest python-font-lock-assignment-statement-multiline-5 () - (python-tests-assert-faces-after-change - "(\\ - a\\ -)\\ - #\\ - 5\\ - ;\\ - (\\ - b\\ - )\\ - #\\ - 6" - '((1) - (8 . font-lock-variable-name-face) (9) - (18 . font-lock-operator-face) (19) - (46 . font-lock-variable-name-face) (47) - (60 . font-lock-operator-face) (61)) - "#" "=")) - -(ert-deftest python-font-lock-assignment-statement-multiline-6 () - (python-tests-assert-faces-after-change - "( - a -)\\ - #\\ - 5\\ - ;\\ - ( - b - )\\ - #\\ - 6" - '((1) - (7 . font-lock-variable-name-face) (8) - (16 . font-lock-operator-face) (17) - (43 . font-lock-variable-name-face) (44) - (56 . font-lock-operator-face) (57)) - "#" "=")) - -(ert-deftest python-font-lock-operator-1 () - (python-tests-assert-faces - "1 << 2 ** 3 == +4%-5|~6&7^8%9" - '((1) - (3 . font-lock-operator-face) (5) - (8 . font-lock-operator-face) (10) - (13 . font-lock-operator-face) (15) - (16 . font-lock-operator-face) (17) - (18 . font-lock-operator-face) (20) - (21 . font-lock-operator-face) (23) - (24 . font-lock-operator-face) (25) - (26 . font-lock-operator-face) (27) - (28 . font-lock-operator-face) (29)))) - -(ert-deftest python-font-lock-operator-2 () - "Keyword operators are font-locked as keywords." - (python-tests-assert-faces - "is_ is None" - '((1) - (5 . font-lock-keyword-face) (7) - (8 . font-lock-constant-face)))) - (ert-deftest python-font-lock-escape-sequence-string-newline () (python-tests-assert-faces "'\\n' From 4897c98b6c496801aad2477c289a40a300eee27f Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Sat, 3 Jun 2023 10:20:08 +0300 Subject: [PATCH 20/23] Fix 'python-util-clone-local-variables' * lisp/progmodes/python.el (python-util-clone-local-variables): Avoid signaling an error when a local variable is unbound. Patch by Ernesto Alfonso . (Bug#63818) --- lisp/progmodes/python.el | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el index 974e07c3c6a..fd196df7550 100644 --- a/lisp/progmodes/python.el +++ b/lisp/progmodes/python.el @@ -6094,7 +6094,8 @@ Optional argument REGEXP selects variables to clone and defaults to \"^python-\"." (mapc (lambda (pair) - (and (symbolp (car pair)) + (and (consp pair) + (symbolp (car pair)) (string-match (or regexp "^python-") (symbol-name (car pair))) (set (make-local-variable (car pair)) From 0eba9cf65119a68596c4bf3689086a517d51ce72 Mon Sep 17 00:00:00 2001 From: Michael Albinus Date: Sat, 3 Jun 2023 09:54:52 +0200 Subject: [PATCH 21/23] * test/infra/Dockerfile.emba (emacs-base): Install also gawk. --- test/infra/Dockerfile.emba | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/infra/Dockerfile.emba b/test/infra/Dockerfile.emba index 7f12d682a13..b146f5a2c4d 100644 --- a/test/infra/Dockerfile.emba +++ b/test/infra/Dockerfile.emba @@ -29,7 +29,7 @@ FROM debian:bullseye as emacs-base RUN apt-get update && \ apt-get install -y --no-install-recommends -o=Dpkg::Use-Pty=0 \ libc-dev gcc g++ make autoconf automake libncurses-dev gnutls-dev \ - libdbus-1-dev libacl1-dev acl git texinfo gdb \ + libdbus-1-dev libacl1-dev acl git texinfo gawk gdb \ && rm -rf /var/lib/apt/lists/* FROM emacs-base as emacs-inotify From 8ec786349e18068bff39b1387bc4a88d62265e34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=99=D0=BE=D1=80=D0=B4=D0=B0=D0=BD=20=D0=9C=D0=B8=D0=BB?= =?UTF-8?q?=D0=B0=D0=B4=D0=B8=D0=BD=D0=BE=D0=B2?= Date: Fri, 26 May 2023 17:23:26 +0300 Subject: [PATCH 22/23] Fix apostrophe handling in rust-ts-mode and go-ts-mode (Bug#63708) * lisp/progmodes/rust-ts-mode.el (rust-ts-mode--syntax-propertize): Treat apostrophes as strings if used to define character literals. Treat LT and GT as pairs if used to define type parameters (formerly they were treated as pairs only for type arguments). * lisp/progmodes/go-ts-mode.el (go-ts-mode--syntax-table): Treat apostrophes as strings if used to define rune literals. Copyright-paperwork-exempt: yes --- lisp/progmodes/go-ts-mode.el | 1 + lisp/progmodes/rust-ts-mode.el | 14 ++++++++++++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/lisp/progmodes/go-ts-mode.el b/lisp/progmodes/go-ts-mode.el index 4233b115f19..698c6424ea2 100644 --- a/lisp/progmodes/go-ts-mode.el +++ b/lisp/progmodes/go-ts-mode.el @@ -58,6 +58,7 @@ (modify-syntax-entry ?< "." table) (modify-syntax-entry ?> "." table) (modify-syntax-entry ?\\ "\\" table) + (modify-syntax-entry ?\' "\"" table) (modify-syntax-entry ?/ ". 124b" table) (modify-syntax-entry ?* ". 23" table) (modify-syntax-entry ?\n "> b" table) diff --git a/lisp/progmodes/rust-ts-mode.el b/lisp/progmodes/rust-ts-mode.el index be06acde3e3..360fcc89491 100644 --- a/lisp/progmodes/rust-ts-mode.el +++ b/lisp/progmodes/rust-ts-mode.el @@ -350,7 +350,10 @@ Return nil if there is no name or if NODE is not a defun node." (treesit-node-child-by-field-name node "name") t)))) (defun rust-ts-mode--syntax-propertize (beg end) - "Apply syntax text property to template delimiters between BEG and END. + "Apply syntax properties to various special characters with +contextual meaning between BEG and END. + +' should be treated as string when used for char literals. < and > are usually punctuation, e.g., as greater/less-than. But when used for types, they should be considered pairs. @@ -359,11 +362,18 @@ This function checks for < and > in the changed RANGES and apply appropriate text property to alter the syntax of template delimiters < and >'s." (goto-char beg) + (while (search-forward "'" end t) + (when (string-equal "char_literal" + (treesit-node-type + (treesit-node-at (match-beginning 0)))) + (put-text-property (match-beginning 0) (match-end 0) + 'syntax-table (string-to-syntax "\"")))) + (goto-char beg) (while (re-search-forward (rx (or "<" ">")) end t) (pcase (treesit-node-type (treesit-node-parent (treesit-node-at (match-beginning 0)))) - ("type_arguments" + ((or "type_arguments" "type_parameters") (put-text-property (match-beginning 0) (match-end 0) 'syntax-table From ede3535051a8f3b209b830adcaba9cb1ddf58685 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Sat, 3 Jun 2023 11:34:11 +0300 Subject: [PATCH 23/23] ; Fix last change * lisp/progmodes/rust-ts-mode.el (rust-ts-mode--syntax-propertize): Doc fix. (Bug#63708) --- lisp/progmodes/rust-ts-mode.el | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lisp/progmodes/rust-ts-mode.el b/lisp/progmodes/rust-ts-mode.el index 360fcc89491..c3cf8d0cf44 100644 --- a/lisp/progmodes/rust-ts-mode.el +++ b/lisp/progmodes/rust-ts-mode.el @@ -350,10 +350,12 @@ Return nil if there is no name or if NODE is not a defun node." (treesit-node-child-by-field-name node "name") t)))) (defun rust-ts-mode--syntax-propertize (beg end) - "Apply syntax properties to various special characters with + "Apply syntax properties to special characters between BEG and END. + +Apply syntax properties to various special characters with contextual meaning between BEG and END. -' should be treated as string when used for char literals. +The apostrophe \\=' should be treated as string when used for char literals. < and > are usually punctuation, e.g., as greater/less-than. But when used for types, they should be considered pairs.