Subject: bug#35383: 27.0.50; Complete process of decoding Gnus group names

From: Eric Abrahamsen <[email-masked]>
Date: Sat, 18 May 2019 13:25:41 -0700

Eric Abrahamsen <[email-masked]> writes:

> Katsumi Yamaoka <[email-masked]> writes:
>
>>> On 04/23/19 17:12 PM, Katsumi Yamaoka wrote:
>>>> Though I'm not quite sure
>>>> yet, the new and the old newsrc.eld files (containing non-ASCII
>>>> nnml and nnrss groups) seem to be compatible with the new and
>>>> the old Gnus mutually.
>>
>> Not mutually but one-way from old Gnus[1] to new Gnus[2] is ok.
>> To activate the groups of the non-ASCII names for the old Gnus,
>> I realized I needed to convert those group names to that of
>>
>> (prin1-to-string (encode-coding-string "Group Name" 'utf-8))
>>
>> one by one in the .newsrc.eld file before starting the old Gnus.
>> No other tweak is necessary to switch back to the old Gnus, and
>> nothing to be done to switch to the new Gnus again.  I verified
>> it with only nnml and nnrss groups as I tried Gnus of the latest
>> git master today for the first time in about a month.
>>
>> [1] currently that of the master and the emacs-26 branches
>> [2] currentlt that of the scratch/gnus-decoded branch
>
> Thanks for the analysis. I think I only had nnimap groups that were
> properly (utf-8) encoded in .newsrc.eld, but still worked with the "old"
> Gnus code (in your sense, above). I guess that was different with
> nnml/nnrss.
>
> I have some more group sorting issues to fix in the current master code,
> then I'll call for testers for the scratch/gnus-decoded branch, then
> hopefully this whole thing can go in.

Before that, I realized that I hadn't updated some of the *Group* buffer
sorting code, for sorting flat groups. The attached patch should go into
master, and then master merged into scratch/gnus-decoded.

Eric

diff --git a/lisp/gnus/gnus-group.el b/lisp/gnus/gnus-group.el
index c757c82fbc..4a14de33b0 100644
--- a/lisp/gnus/gnus-group.el
+++ b/lisp/gnus/gnus-group.el
@@ -3300,21 +3300,31 @@ gnus-group-sort-groups
   (funcall gnus-group-sort-alist-function
 	   (gnus-make-sort-function func) reverse)
   (gnus-group-unmark-all-groups)
+  ;; Redisplay all groups according to the newly-sorted order of
+  ;; `gnus-group-list'.
   (gnus-group-list-groups)
   (gnus-dribble-touch))
 
 (defun gnus-group-sort-flat (func reverse)
-  ;; We peel off the dummy group from the alist.
+  "Sort groups in a flat list using sorting function FUNC.
+If REVERSE is non-nil, reverse the sort order.
+
+This function sets a new value for `gnus-group-list'; its return
+value is disregarded."
   (when func
-    (when (equal (gnus-info-group (car gnus-newsrc-alist)) "dummy.group")
-      (pop gnus-newsrc-alist))
-    ;; Do the sorting.
-    (setq gnus-newsrc-alist
-	  (sort gnus-newsrc-alist func))
-    (when reverse
-      (setq gnus-newsrc-alist (nreverse gnus-newsrc-alist)))
-    ;; Regenerate the hash table.
-    (gnus-make-hashtable-from-newsrc-alist)))
+    (let* ((groups (remove "dummy.group" gnus-group-list))
+	   (sorted-infos
+	    (sort (mapcar (lambda (g)
+			    (gnus-get-info g))
+			  groups)
+		  func)))
+      (setq gnus-group-list
+	    (mapcar (lambda (i)
+		      (gnus-info-group i))
+		    sorted-infos))
+      (when reverse
+	(setq gnus-group-list (nreverse gnus-group-list)))
+      (setq gnus-group-list (cons "dummy.group" gnus-group-list)))))
 
 (defun gnus-group-sort-groups-by-alphabet (&optional reverse)
   "Sort the group buffer alphabetically by group name.
@@ -3377,27 +3387,26 @@ gnus-group-sort-selected-groups
     (gnus-dribble-touch)))
 
 (defun gnus-group-sort-selected-flat (groups func reverse)
-  (let (entries infos)
-    ;; First find all the group entries for these groups.
-    (while groups
-      (push (nthcdr 2 (gnus-group-entry (pop groups)))
-	    entries))
-    ;; Then sort the infos.
-    (setq infos
-	  (sort
-	   (mapcar
-	    (lambda (entry) (car entry))
-	    (setq entries (nreverse entries)))
-	   func))
+  "Sort only the selected GROUPS, using FUNC.
+If REVERSE is non-nil, reverse the sorting."
+  (let ((infos (sort
+		(mapcar (lambda (g)
+			  (gnus-get-info g))
+			groups)
+		func))
+	sorted-groups)
     (when reverse
       (setq infos (nreverse infos)))
-    ;; Go through all the infos and replace the old entries
-    ;; with the new infos.
-    (while infos
-      (setcar (car entries) (pop infos))
-      (pop entries))
-    ;; Update the hashtable.
-    (gnus-make-hashtable-from-newsrc-alist)))
+    (setq sorted-groups (mapcar (lambda (i) (gnus-info-group i)) infos))
+
+    ;; Find the original locations of GROUPS in `gnus-group-list', and
+    ;; replace each one, in order, with a group from SORTED-GROUPS.
+    (dolist (i (sort (mapcar (lambda (g)
+			       (seq-position gnus-group-list g))
+			     groups)
+		     #'<))
+      (setf (nth i gnus-group-list)
+	    (pop sorted-groups)))))
 
 (defun gnus-group-sort-selected-groups-by-alphabet (&optional n reverse)
   "Sort the group buffer alphabetically by group name.
diff --git a/lisp/gnus/gnus-start.el b/lisp/gnus/gnus-start.el
index 2f8a260bf1..16d167613e 100644
--- a/lisp/gnus/gnus-start.el
+++ b/lisp/gnus/gnus-start.el
@@ -583,11 +583,11 @@ gnus-subscribe-randomly
 
 (defun gnus-subscribe-alphabetically (newgroup)
   "Subscribe new NEWGROUP and insert it in alphabetical order."
-  (let ((groups (cdr gnus-newsrc-alist))
+  (let ((groups (cdr gnus-group-list))
 	before)
     (while (and (not before) groups)
-      (if (string< newgroup (caar groups))
-	  (setq before (caar groups))
+      (if (string< newgroup (car groups))
+	  (setq before (car groups))
 	(setq groups (cdr groups))))
     (gnus-subscribe-newsgroup newgroup before)))
 
@@ -618,15 +618,15 @@ gnus-subscribe-interactively
 it is killed."
   (if (gnus-y-or-n-p (format "Subscribe new newsgroup %s? " group))
       (gnus-subscribe-hierarchically group)
-    (push group gnus-killed-list)))
+    (gnus-subscribe-killed group)))
 
 (defun gnus-subscribe-zombies (group)
   "Make the new GROUP into a zombie group."
-  (push group gnus-zombie-list))
+  (cl-pushnew group gnus-zombie-list :test #'equal))
 
 (defun gnus-subscribe-killed (group)
   "Make the new GROUP a killed group."
-  (push group gnus-killed-list))
+  (cl-pushnew group gnus-killed-list :test #'equal))
 
 (defun gnus-subscribe-newsgroup (newsgroup &optional next)
   "Subscribe new NEWSGROUP.