Subject: bug#56329: 29.0.50; [PATCH] RET at EOB of *Server* (gnus)

From: [email-masked]
Date: Thu, 30 Jun 2022 17:03:25 -0400

All gnus buffers round up to the nearest nonempty
line upon RET at eob.  Finally do the same for
*Server*.

>From 5ea2dd8722430d257c5e50b49bac0c8af344b58a Mon Sep 17 00:00:00 2001
From: dickmao <[email-masked]>
Date: Thu, 30 Jun 2022 16:54:57 -0400
Subject: [PATCH] Round up to nonempty line gnus server mode

* doc/lispref/text.texi (Property Search): Typo.
* lisp/gnus/gnus-srvr.el (gnus-server--server-name,
gnus-server-server-name, gnus-server-named-server):
Round up to nearest nonempty line.
* test/lisp/gnus/gnus-tests.el (gnus-test-basic-op,
gnus-test-server-at-eob): Test it.
---
 doc/lispref/text.texi        |  2 +-
 lisp/gnus/gnus-srvr.el       | 15 +++++--
 test/lisp/gnus/gnus-tests.el | 78 ++++++++++++++++++++++++++++++++++--
 3 files changed, 87 insertions(+), 8 deletions(-)

diff --git a/doc/lispref/text.texi b/doc/lispref/text.texi
index 622f03d2a85..0c04d01261b 100644
--- a/doc/lispref/text.texi
+++ b/doc/lispref/text.texi
@@ -3485,7 +3485,7 @@ Property Search
 @end defun
 
 @defun text-property-search-backward prop &optional value predicate not-current
-This is just like @code{text-property-search-backward}, but searches
+This is just like @code{text-property-search-forward}, but searches
 backward instead.  Point is placed at the beginning of the matched
 region instead of the end, though.
 @end defun
diff --git a/lisp/gnus/gnus-srvr.el b/lisp/gnus/gnus-srvr.el
index a520bfcd8b1..9600503645a 100644
--- a/lisp/gnus/gnus-srvr.el
+++ b/lisp/gnus/gnus-srvr.el
@@ -338,15 +338,22 @@ gnus-server-prepare
   (goto-char (point-min))
   (gnus-server-position-point))
 
+(defsubst gnus-server--server-name (which)
+  (when-let ((server
+              (save-excursion
+                (let (prop)
+                  (while (and (null (setq prop (get-text-property (point-at-bol) which)))
+                              (zerop (forward-line -1))))
+                  prop))))
+    (symbol-name server)))
+
 (defun gnus-server-server-name ()
-  (let ((server (get-text-property (point-at-bol) 'gnus-server)))
-    (and server (symbol-name server))))
+  (gnus-server--server-name 'gnus-server))
 
 (defun gnus-server-named-server ()
   "Return a server name that matches one of the names returned by
 `gnus-method-to-server'."
-  (let ((server (get-text-property (point-at-bol) 'gnus-named-server)))
-    (and server (symbol-name server))))
+  (gnus-server--server-name 'gnus-named-server))
 
 (defalias 'gnus-server-position-point 'gnus-goto-colon)
 
diff --git a/test/lisp/gnus/gnus-tests.el b/test/lisp/gnus/gnus-tests.el
index 4c5a6a8191c..11f06b50d41 100644
--- a/test/lisp/gnus/gnus-tests.el
+++ b/test/lisp/gnus/gnus-tests.el
@@ -25,9 +25,81 @@
 ;; tests that are not standalone.
 
 ;;; Code:
-;; registry.el is required by gnus-registry.el but this way we're explicit.
-(require 'registry)
-(require 'gnus-registry)
+(require 'cl-macs)
+(require 'message)
+(require 'gnus)
+(require 'gnus-start)
+(require 'gnus-group)
+(require 'nsm)
+
+(defconst gnus-tests-load-file-name (or load-file-name
+                                        (buffer-file-name)))
+
+(defmacro gnus-tests-let-customs (bindings &rest forms)
+  (declare (indent defun))
+  `(progn
+     (funcall #'custom-set-variables
+              ,@(mapcar (apply-partially #'list 'quote) bindings))
+     ,@forms))
+
+(cl-defmacro gnus-tests-doit (&rest
+                              body
+                              &key
+                              (select-method)
+                              (customs)
+                              &allow-other-keys
+                              &aux
+                              (body
+                               (cl-loop until (not (keywordp (car body)))
+                                        do (setq body (nthcdr 2 body))
+                                        finally return body)))
+  (declare (indent defun))
+  `(let* ((parent-dir (file-name-directory gnus-tests-load-file-name))
+          (default-directory (file-name-as-directory (concat parent-dir "gnus-tests")))
+	  (user-emacs-directory default-directory))
+     (unless (file-exists-p default-directory)
+       (make-directory default-directory))
+     (gnus-tests-let-customs
+       ((gnus-verbose 8)
+        (gnus-home-directory default-directory)
+        (gnus-use-dribble-file nil)
+        (network-security-level (quote low))
+        (gnus-interactive-exit (quote quiet))
+        ,@(when select-method (list `(gnus-select-method ',select-method)))
+        (message-directory (concat gnus-home-directory "Mail"))
+        (mail-source-directory (concat gnus-home-directory "Mail"))
+        (mail-source-crash-box (concat gnus-home-directory ".whatev"))
+        (gnus-startup-file (nnheader-concat gnus-home-directory ".newsrc.eld"))
+        (gnus-init-file (nnheader-concat gnus-home-directory ".gnus"))
+        (gnus-directory (nnheader-concat gnus-home-directory "News/"))
+        ,@customs)
+       (unwind-protect
+           (progn ,@body)
+         (cl-macrolet ((safe-delete
+                         (x)
+                         `(if (cl-search "gnus-tests/" ,x)
+                              (delete-directory ,x t)
+                            (error "Attempted delete of %s!" ,x))))
+           (safe-delete gnus-home-directory))))))
+
+(ert-deftest gnus-test-basic-op ()
+  (gnus-tests-doit :select-method (nnfolder "")
+    (call-interactively #'gnus)
+    (call-interactively #'gnus-group-exit)))
+
+(ert-deftest gnus-test-server-at-eob ()
+  "`gnus-server-read-server' looks to nearest nonempty line."
+  (gnus-tests-doit :select-method (nnfolder "")
+    (call-interactively #'gnus)
+    (call-interactively #'gnus-group-enter-server-mode)
+    (with-current-buffer gnus-server-buffer
+      (should-error (search-forward "foobar"))
+      (search-forward "nnfolder")
+      (goto-char (point-max))
+      (should (gnus-server-server-name))
+      (goto-char (point-min))
+      (should (gnus-server-server-name)))
+    (call-interactively #'gnus-group-exit)))
 
 (provide 'gnus-tests)
 ;;; gnus-tests.el ends here
-- 
2.36.1

In Commercial Emacs 0.3.1snapshot 5de4c3d in dev (upstream 29.0.50, x86_64-pc-linux-gnu) built on dick
Repository revision: 5de4c3deabbd44bd3b9e1aaa52e23237af9c7f3e
Repository branch: dev
Windowing system distributor 'The X.Org Foundation', version 11.0.12013000
System Description: Ubuntu 20.04.4 LTS

Configured using:
 'configure --prefix=/home/dick/.local --with-tree-sitter'
Configured features:
CAIRO DBUS FREETYPE GIF GLIB GMP GNUTLS GSETTINGS HARFBUZZ JPEG JSON
TREE_SITTER LCMS2 LIBSELINUX LIBXML2 MODULES NOTIFY INOTIFY PDUMPER PNG
RSVG SECCOMP SOUND THREADS TIFF TOOLKIT_SCROLL_BARS WEBP X11 XDBE XIM
XINPUT2 XPM GTK3 ZLIB
Important settings:
  value of $LANG: en_US.UTF-8
  locale-coding-system: utf-8-unix

Major mode: Magit

Minor modes in effect:
  global-git-commit-mode: t
  shell-dirtrack-mode: t
  projectile-mode: t
  flx-ido-mode: t
  override-global-mode: t
  global-hl-line-mode: t
  hl-line-mode: t
  winner-mode: t
  tooltip-mode: t
  show-paren-mode: t
  mouse-wheel-mode: t
  file-name-shadow-mode: t
  global-font-lock-mode: t
  font-lock-mode: t
  blink-cursor-mode: t
  buffer-read-only: t
  column-number-mode: t
  line-number-mode: t
  transient-mark-mode: t
  auto-composition-mode: t
  auto-encryption-mode: t
  auto-compression-mode: t

Load-path shadows:
/home/dick/gomacro-mode/gomacro-mode hides /home/dick/.emacs.d/elpa/gomacro-mode-20200326.1103/gomacro-mode
/home/dick/.emacs.d/elpa/go-rename-20190805.2101/go-rename hides /home/dick/.emacs.d/elpa/go-mode-1.6.0/go-rename
/home/dick/.emacs.d/elpa/go-guru-20181012.330/go-guru hides /home/dick/.emacs.d/elpa/go-mode-1.6.0/go-guru
/home/dick/org-gcal.el/org-gcal hides /home/dick/.emacs.d/elpa/org-gcal-0.3/org-gcal
/home/dick/.emacs.d/elpa/request-deferred-0.2.0/request-deferred hides /home/dick/.emacs.d/elpa/request-0.3.3/request-deferred
/home/dick/.emacs.d/elpa/chess-2.0.5/_pkg hides /home/dick/.local/share/emacs/site-lisp/_pkg
/home/dick/.emacs.d/elpa/chess-2.0.5/chess-pos hides /home/dick/.local/share/emacs/site-lisp/chess-pos
/home/dick/.emacs.d/elpa/chess-2.0.5/chess-module hides /home/dick/.local/share/emacs/site-lisp/chess-module
/home/dick/.emacs.d/elpa/chess-2.0.5/chess-ucb hides /home/dick/.local/share/emacs/site-lisp/chess-ucb
/home/dick/.emacs.d/elpa/chess-2.0.5/chess-scid hides /home/dick/.local/share/emacs/site-lisp/chess-scid
/home/dick/.emacs.d/elpa/chess-2.0.5/chess-puzzle hides /home/dick/.local/share/emacs/site-lisp/chess-puzzle
/home/dick/.emacs.d/elpa/chess-2.0.5/chess-irc hides /home/dick/.local/share/emacs/site-lisp/chess-irc
/home/dick/.emacs.d/elpa/chess-2.0.5/chess-network hides /home/dick/.local/share/emacs/site-lisp/chess-network
/home/dick/.emacs.d/elpa/chess-2.0.5/chess-autosave hides /home/dick/.local/share/emacs/site-lisp/chess-autosave
/home/dick/.emacs.d/elpa/chess-2.0.5/chess-engine hides /home/dick/.local/share/emacs/site-lisp/chess-engine
/home/dick/.emacs.d/elpa/chess-2.0.5/chess-tutorial hides /home/dick/.local/share/emacs/site-lisp/chess-tutorial
/home/dick/.emacs.d/elpa/chess-2.0.5/chess-german hides /home/dick/.local/share/emacs/site-lisp/chess-german
/home/dick/.emacs.d/elpa/chess-2.0.5/chess-file hides /home/dick/.local/share/emacs/site-lisp/chess-file
/home/dick/.emacs.d/elpa/chess-2.0.5/chess-random hides /home/dick/.local/share/emacs/site-lisp/chess-random
/home/dick/.emacs.d/elpa/chess-2.0.5/chess-stockfish hides /home/dick/.local/share/emacs/site-lisp/chess-stockfish
/home/dick/.emacs.d/elpa/chess-2.0.5/chess-pgn hides /home/dick/.local/share/emacs/site-lisp/chess-pgn
/home/dick/.emacs.d/elpa/chess-2.0.5/chess-kibitz hides /home/dick/.local/share/emacs/site-lisp/chess-kibitz
/home/dick/.emacs.d/elpa/chess-2.0.5/chess-eco hides /home/dick/.local/share/emacs/site-lisp/chess-eco
/home/dick/.emacs.d/elpa/chess-2.0.5/chess-display hides /home/dick/.local/share/emacs/site-lisp/chess-display
/home/dick/.emacs.d/elpa/chess-2.0.5/chess-var hides /home/dick/.local/share/emacs/site-lisp/chess-var
/home/dick/.emacs.d/elpa/chess-2.0.5/chess-test hides /home/dick/.local/share/emacs/site-lisp/chess-test
/home/dick/.emacs.d/elpa/chess-2.0.5/chess-ply hides /home/dick/.local/share/emacs/site-lisp/chess-ply
/home/dick/.emacs.d/elpa/chess-2.0.5/chess-message hides /home/dick/.local/share/emacs/site-lisp/chess-message
/home/dick/.emacs.d/elpa/chess-2.0.5/chess-ics1 hides /home/dick/.local/share/emacs/site-lisp/chess-ics1
/home/dick/.emacs.d/elpa/chess-2.0.5/chess-phalanx hides /home/dick/.local/share/emacs/site-lisp/chess-phalanx
/home/dick/.emacs.d/elpa/chess-2.0.5/chess-game hides /home/dick/.local/share/emacs/site-lisp/chess-game
/home/dick/.emacs.d/elpa/chess-2.0.5/chess-log hides /home/dick/.local/share/emacs/site-lisp/chess-log
/home/dick/.emacs.d/elpa/chess-2.0.5/chess-plain hides /home/dick/.local/share/emacs/site-lisp/chess-plain
/home/dick/.emacs.d/elpa/chess-2.0.5/chess-perft hides /home/dick/.local/share/emacs/site-lisp/chess-perft
/home/dick/.emacs.d/elpa/chess-2.0.5/chess-glaurung hides /home/dick/.local/share/emacs/site-lisp/chess-glaurung
/home/dick/.emacs.d/elpa/chess-2.0.5/chess-ai hides /home/dick/.local/share/emacs/site-lisp/chess-ai
/home/dick/.emacs.d/elpa/chess-2.0.5/chess-fruit hides /home/dick/.local/share/emacs/site-lisp/chess-fruit
/home/dick/.emacs.d/elpa/chess-2.0.5/chess-uci hides /home/dick/.local/share/emacs/site-lisp/chess-uci
/home/dick/.emacs.d/elpa/chess-2.0.5/chess-epd hides /home/dick/.local/share/emacs/site-lisp/chess-epd
/home/dick/.emacs.d/elpa/chess-2.0.5/chess-database hides /home/dick/.local/share/emacs/site-lisp/chess-database
/home/dick/.emacs.d/elpa/chess-2.0.5/chess-link hides /home/dick/.local/share/emacs/site-lisp/chess-link
/home/dick/.emacs.d/elpa/chess-2.0.5/chess-transport hides /home/dick/.local/share/emacs/site-lisp/chess-transport
/home/dick/.emacs.d/elpa/chess-2.0.5/chess-none hides /home/dick/.local/share/emacs/site-lisp/chess-none
/home/dick/.emacs.d/elpa/chess-2.0.5/chess-polyglot hides /home/dick/.local/share/emacs/site-lisp/chess-polyglot
/home/dick/.emacs.d/elpa/chess-2.0.5/chess-crafty hides /home/dick/.local/share/emacs/site-lisp/chess-crafty
/home/dick/.emacs.d/elpa/chess-2.0.5/chess-chat hides /home/dick/.local/share/emacs/site-lisp/chess-chat
/home/dick/.emacs.d/elpa/chess-2.0.5/chess hides /home/dick/.local/share/emacs/site-lisp/chess
/home/dick/.emacs.d/elpa/chess-2.0.5/chess-images hides /home/dick/.local/share/emacs/site-lisp/chess-images
/home/dick/.emacs.d/elpa/chess-2.0.5/chess-gnuchess hides /home/dick/.local/share/emacs/site-lisp/chess-gnuchess
/home/dick/.emacs.d/elpa/chess-2.0.5/chess-fen hides /home/dick/.local/share/emacs/site-lisp/chess-fen
/home/dick/.emacs.d/elpa/chess-2.0.5/chess-ics hides /home/dick/.local/share/emacs/site-lisp/chess-ics
/home/dick/.emacs.d/elpa/chess-2.0.5/chess-ics2 hides /home/dick/.local/share/emacs/site-lisp/chess-ics2
/home/dick/.emacs.d/elpa/chess-2.0.5/chess-common hides /home/dick/.local/share/emacs/site-lisp/chess-common
/home/dick/.emacs.d/elpa/chess-2.0.5/chess-input hides /home/dick/.local/share/emacs/site-lisp/chess-input
/home/dick/.emacs.d/elpa/chess-2.0.5/chess-announce hides /home/dick/.local/share/emacs/site-lisp/chess-announce
/home/dick/.emacs.d/elpa/chess-2.0.5/chess-clock hides /home/dick/.local/share/emacs/site-lisp/chess-clock
/home/dick/.emacs.d/elpa/chess-2.0.5/chess-sound hides /home/dick/.local/share/emacs/site-lisp/chess-sound
/home/dick/.emacs.d/elpa/chess-2.0.5/chess-sjeng hides /home/dick/.local/share/emacs/site-lisp/chess-sjeng
/home/dick/.emacs.d/elpa/chess-2.0.5/chess-algebraic hides /home/dick/.local/share/emacs/site-lisp/chess-algebraic
/home/dick/.emacs.d/elpa/transient-0.3.7snapshot/transient hides /home/dick/.local/share/emacs/0.3.1/lisp/transient

Features:
(shadow bbdb-message footnote emacsbug texinfo texinfo-loaddefs
face-remap magit-patch-changelog magit-patch magit-submodule
magit-obsolete magit-blame magit-stash magit-reflog magit-bisect
magit-push magit-pull magit-fetch magit-clone magit-remote magit-commit
magit-sequence magit-notes magit-worktree magit-tag magit-merge
magit-branch magit-reset magit-files magit-refs magit-status magit
magit-repos magit-apply magit-wip magit-log which-func imenu magit-diff
smerge-mode diff git-commit log-edit pcvs-util add-log magit-core
magit-margin magit-transient magit-process with-editor server magit-mode
transient misearch multi-isearch vc-git diff-mode vc-dispatcher
bug-reference tramp-archive tramp-gvfs tramp-cache zeroconf textsec
uni-scripts idna-mapping ucs-normalize uni-confusable textsec-check sort
smiley mm-archive mail-extr qp gnus-async gnus-ml gnus-notifications
gnus-fun notifications gnus-kill gnus-dup disp-table utf-7 blamer a
tramp tramp-loaddefs trampver tramp-integration cus-start files-x
tramp-compat shell pcomplete ls-lisp url-cache benchmark nnrss nnfolder
nndiscourse rbenv nnhackernews nntwitter nntwitter-api bbdb-gnus
gnus-demon nntp nnmairix nnml nnreddit gnus-topic url-http url-auth
url-gw network-stream nsm request virtualenvwrapper gud s json-rpc
python gnus-score score-mode gnus-bcklg gnus-srvr gnus-cite anaphora
bbdb-mua bbdb-com bbdb bbdb-site timezone gnus-delay gnus-draft
gnus-cache gnus-agent gnus-msg gnus-art mm-uu mml2015 mm-view mml-smime
smime gnutls dig gnus-sum shr pixel-fill kinsoku url-file url-dired svg
dom nndraft nnmh gnus-group mm-url gnus-undo use-package
use-package-delight use-package-diminish gnus-start gnus-dbus dbus xml
gnus-cloud nnimap nnmail mail-source utf7 netrc nnoo parse-time iso8601
gnus-spec gnus-int gnus-range message sendmail yank-media puny dired-x
dired dired-loaddefs rfc822 mml mml-sec epa epg rfc6068 epg-config
mm-decode mm-bodies mm-encode mail-parse rfc2231 rfc2047 rfc2045
ietf-drums mailabbrev gmm-utils mailheader gnus-win paredit-ext paredit
inf-ruby ruby-mode smie company pcase haskell-interactive-mode
haskell-presentation-mode haskell-process haskell-session
haskell-compile haskell-mode haskell-cabal haskell-utils
haskell-font-lock haskell-indentation haskell-string
haskell-sort-imports haskell-lexeme haskell-align-imports
haskell-complete-module haskell-ghc-support noutline outline
flymake-proc flymake warnings etags fileloop generator dabbrev
haskell-customize hydra lv use-package-ensure solarized-theme
solarized-definitions projectile lisp-mnt ibuf-ext ibuffer
ibuffer-loaddefs thingatpt magit-autorevert autorevert filenotify
magit-git magit-base magit-section format-spec crm dash rx compat-27
compat-26 compat grep compile comint ansi-color gnus nnheader range
mail-utils mm-util mail-prsvr gnus-util text-property-search time-date
flx-ido flx google-translate-default-ui google-translate-core-ui
facemenu color ido google-translate-core google-translate-tk
google-translate-backend use-package-bind-key bind-key auto-complete
easy-mmode advice edmacro kmacro popup cus-edit pp cus-load wid-edit
emms-player-mplayer emms-player-simple emms emms-compat cl-extra
help-mode xref project use-package-core derived hl-line winner ring
debbugs-autoloads eglot-autoloads elpaso-disc-autoloads elpaso-autoloads
find-func finder-inf go-mode-autoloads json-reformat-autoloads
json-snatcher-autoloads projectile-autoloads sml-mode-autoloads
epl-autoloads tornado-template-mode-autoloads typescript-mode-autoloads
request-autoloads info package browse-url url url-proxy url-privacy
url-expand url-methods url-history url-cookie generate-lisp-file
url-domsuf url-util mailcap url-handlers url-parse auth-source cl-seq
eieio eieio-core cl-macs eieio-loaddefs password-cache json subr-x map
byte-opt gv bytecomp byte-compile cconv cldefs url-vars cl-loaddefs
cl-lib rmc iso-transl tooltip eldoc paren electric uniquify ediff-hook
vc-hooks lisp-float-type elisp-mode mwheel term/x-win x-win
term/common-win x-dnd tool-bar dnd fontset image regexp-opt fringe
tree-sitter tabulated-list replace newcomment text-mode lisp-mode
prog-mode register page tab-bar menu-bar rfn-eshadow isearch easymenu
timer select scroll-bar mouse jit-lock font-lock syntax font-core
term/tty-colors frame minibuffer nadvice seq simple cl-generic
indonesian philippine cham georgian utf-8-lang misc-lang vietnamese
tibetan thai tai-viet lao korean japanese eucjp-ms cp51932 hebrew greek
romanian slovak czech european ethiopic indian cyrillic chinese
composite emoji-zwj charscript charprop case-table epa-hook
jka-cmpr-hook help abbrev obarray oclosure cl-preloaded button loaddefs
faces cus-face macroexp files window text-properties overlay sha1 md5
base64 format env code-pages mule custom widget keymap
hashtable-print-readable backquote threads dbusbind inotify lcms2
dynamic-setting system-font-setting font-render-setting cairo
move-toolbar gtk x-toolkit xinput2 x multi-tty make-network-process
emacs)

Memory information:
((conses 16 783218 54430)
 (symbols 48 37763 3)
 (strings 32 180625 21495)
 (string-bytes 1 5209192)
 (vectors 16 100876)
 (vector-slots 8 2245530 58785)
 (floats 8 1097 1257)
 (intervals 56 3626 269)
 (buffers 1000 35))