unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* Proposal: Control help- and Info-mode buffers from other buffers
@ 2023-05-30 12:38 Arthur Miller
  0 siblings, 0 replies; only message in thread
From: Arthur Miller @ 2023-05-30 12:38 UTC (permalink / raw)
  To: emacs-devel

[-- Attachment #1: Type: text/plain, Size: 587 bytes --]


Previously today I have sent in a proposal and a patch to make help- and
Info-mode "remotely" operable (from other buffers). Unfortunately, I have
discovered som copy-pasta errors, and as well some unnecessary byte-compiler
errors, due to where I placed certain function; I guess I hade those definitions
already in my sessions while I tested. Here is the same patch, but I have
furnitured around some code, fixed copy-pasta in the docs and as well replaced
acronym names I have used for local variables for more self-documenting names.

Sorry for not seeing it in the original patch.


[-- Attachment #2: 0001-Use-help-and-Info-mode-commands-from-any-buffer.patch --]
[-- Type: text/x-patch, Size: 82312 bytes --]

From 04334fe2a97d8f21f684fa2860f343b4a236a391 Mon Sep 17 00:00:00 2001
From: Arthur Miller <arthur.miller@live.com>
Date: Tue, 30 May 2023 14:09:42 +0200
Subject: [PATCH] Use help- and Info-mode commands from any buffer

Allow commands that act on help-mode and Info-mode to be called from other
buffers than just help and Info buffer.
* etc/NEWS: Mention the change.
* doc/emacs/help.texi: Update relevant commands mentioned in the text.
* lisp/help-mode.el (help-jump):
New symbol used for both command and global variable.
Command jumps to/from help window; var records 'jumped from'.
* lisp/help-mode.el (help-view-source):
* lisp/help-mode.el (help-goto-info):
* lisp/help-mode.el (help-go-back):
* lisp/help-mode.el (help-go-forward):
* lisp/help-mode.el (help-goto-next-page):
* lisp/help-mode.el (help-goto-previous-page):
* lisp/help-mode.el (help-goto-lispref-info):
* lisp/help-mode.el (help-customize):
Help-mode commands adapted to be called from any buffer.
* lisp/help-mode.el (help-quit-window):
* lisp/help-mode.el (help-revert-buffer):
* lisp/help-mode.el (help-describe-mode):
* lisp/help-mode.el (help-beginning-of-buffer):
* lisp/help-mode.el (help-end-of-buffer):
* lisp/help-mode.el (help-scroll-up-command):
* lisp/help-mode.el (help-scroll-down-command):
* lisp/help-mode.el (help-forward-button):
* lisp/help-mode.el (help-backward-button):
* lisp/help-mode.el (help-button-describe):
* lisp/help-mode.el (help-push-button):
New commands. Do what they wrapped counterparts without 'help-'
prefix do, but specifically in help buffer.
* lisp/help-mode.el (help-mode-map):
* lisp/help-mode.el (help-mode-menu):
Update bindings to reflect the new commands for previously
generic commands Bind help-jump to 'j' (previously unused).
* lisp/help-mode.el (help-mode-prefix-key):
New defcustom declaration. Prefix key for help-mode-map.
* lisp/info.el (Info-mode-prefix-key):
New defcustom declaration. Prefix key for Info-mode-map.
* lisp/info.el (Info-menu):
* lisp/info.el (Info-next):
* lisp/info.el (Info-prev):
* lisp/info.el (Info-up):
* lisp/info.el (Info-history-back):
* lisp/info.el (Info-history-forward):
* lisp/info.el (Info-directory):
* lisp/info.el (Info-toc):
* lisp/info.el (Info-nth-menu-item):
* lisp/info.el (Info-top-node):
* lisp/info.el (Info-final-node):
* lisp/info.el (Info-forward-node):
* lisp/info.el (Info-backward-node):
* lisp/info.el (Info-next-menu-item):
* lisp/info.el (Info-last-menu-item):
* lisp/info.el (Info-next-preorder):
* lisp/info.el (Info-last-preorder):
* lisp/info.el (Info-scroll-up):
* lisp/info.el (Info-scroll-down):
* lisp/info.el (Info-next-reference):
* lisp/info.el (Info-prev-reference):
* lisp/info.el (Info-index):
* lisp/info.el (Info-index-next):
* lisp/info.el (Info-virtual-next):
* lisp/info.el (Info-apropos):
* lisp/info.el (Info-finder):
* lisp/info.el (Info-summary):
* lisp/info.el (Info-copy-current-node-name):
Info-mode commands adapted to be called from any buffer.
* lisp/info.el (Info-describe-mode):
* lisp/info.el (Info-quit-window):
* lisp/info.el (Info-beginning-of-buffer):
* lisp/info.el (Info-end-of-buffer):
New commands. Do what they wrapped counterparts without 'Info-'
prefix do, but specifically in Info buffer.
* lisp/info.el (Info-jump):
New symbol used for both command and global variable.
Command jumps to/from Info window; var records 'jumped from'.
* lisp/info.el (Info-mode-map):
* lisp/info.el (Info-mode-menu):
Update bindings to reflect the new commands for previously
generic commands Bind Info-jump to 'j' (previously unused).
---
 doc/emacs/help.texi |   12 +-
 etc/NEWS            |   19 +
 lisp/help-mode.el   |  260 ++++++++--
 lisp/info.el        | 1156 +++++++++++++++++++++++++------------------
 4 files changed, 928 insertions(+), 519 deletions(-)

diff --git a/doc/emacs/help.texi b/doc/emacs/help.texi
index 945e12a05d2..b50905c3dc4 100644
--- a/doc/emacs/help.texi
+++ b/doc/emacs/help.texi
@@ -494,9 +494,9 @@ Help Mode
 @item @key{RET}
 Follow a cross reference at point (@code{help-follow}).
 @item @key{TAB}
-Move point forward to the next hyperlink (@code{forward-button}).
+Move point forward to the next hyperlink (@code{help-forward-button}).
 @item S-@key{TAB}
-Move point back to the previous hyperlink (@code{backward-button}).
+Move point back to the previous hyperlink (@code{help-backward-button}).
 @item mouse-1
 @itemx mouse-2
 Follow a hyperlink that you click on.
@@ -544,12 +544,12 @@ Help Mode
 (@code{help-go-forward}).
 
 @kindex TAB @r{(Help mode)}
-@findex forward-button
+@findex help-forward-button
 @kindex S-TAB @r{(Help mode)}
-@findex backward-button
+@findex help-backward-button
   To move between hyperlinks in a help buffer, use @key{TAB}
-(@code{forward-button}) to move forward to the next hyperlink and
-@kbd{S-@key{TAB}} (@code{backward-button}) to move back to the
+(@code{help-forward-button}) to move forward to the next hyperlink and
+@kbd{S-@key{TAB}} (@code{help-backward-button}) to move back to the
 previous hyperlink.  These commands act cyclically; for instance,
 typing @key{TAB} at the last hyperlink moves back to the first
 hyperlink.
diff --git a/etc/NEWS b/etc/NEWS
index 3c71e52fff4..fe241d604cb 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -30,6 +30,25 @@ applies, and please also update docstrings as needed.
 \f
 * Changes in Emacs 30.1
 
++++
+** New user option 'info-mode-prefix-key.
+Prefix key for `Info-mode-map, so it can be used from other buffer but
+just *info* buffer.
+
+** Commands acting on Info buffer can now be used from any buffer
+Similar to help-mode, keyboard-driven commands acting in Info-mode and
+bound in Info-mode-map can now be used from any buffer (acting on Info
+buffer).
++++
+** New user option 'help-mode-prefix-key'.
+The key is used to assign `help-mode-map' to a prefix, so it can be
+used as a prefix-key from other buffers but just *Help* buffer.
+
+** Commands acting on Help buffer can now be used from any buffer
+This means that all commands that normally required a user to switch
+to *Help* buffer before the invocation, can now be invoked from any
+buffer. With other words, you can now control Help buffer from any
+other buffer, which lessens amount of switching between buffers.
 ---
 ** New user option 'describe-bindings-outline-rules'.
 This user option controls outline visibility in the output buffer of
diff --git a/lisp/help-mode.el b/lisp/help-mode.el
index bf64d032b65..af41686e3fd 100644
--- a/lisp/help-mode.el
+++ b/lisp/help-mode.el
@@ -47,7 +47,22 @@ help-mode-map
   "s"             #'help-view-source
   "I"             #'help-goto-lispref-info
   "i"             #'help-goto-info
-  "c"             #'help-customize)
+  "j"             #'help-jump
+  "c"             #'help-customize
+  "g"             #'help-revert-buffer
+  "q"             #'help-quit-window
+  "<"             #'help-beginning-of-buffer
+  ">"             #'help-end-of-buffer
+  "h"             #'help-describe-mode
+  "?"             #'help-describe-mode
+  "DEL"           #'help-scroll-down-command
+  "SPC"           #'help-scroll-down-command
+  "S-SPC"         #'help-scroll-up-command
+  "RET"           #'help-push-button
+  "TAB"           #'help-forward-button
+  "C-M-i"         #'help-backward-button
+  "<backtab>"     #'help-backward-button
+  "ESC TAB"       #'help-backward-button)
 
 (easy-menu-define help-mode-menu help-mode-map
   "Menu for Help mode."
@@ -60,9 +75,9 @@ help-mode-menu
     ["Next Topic" help-go-forward
      :help "Go back to next topic in this help buffer"
      :active help-xref-forward-stack]
-    ["Move to Previous Button" backward-button
+    ["Move to Previous Button" help-backward-button
      :help "Move to the Previous Button in the help buffer"]
-    ["Move to Next Button" forward-button
+    ["Move to Next Button" help-forward-button
      :help "Move to the Next Button in the help buffer"]
     ["View Source" help-view-source
      :help "Go to the source file for the current help item"]
@@ -150,6 +165,22 @@ help-mode-hook
   "Hook run by `help-mode'."
   :type 'hook
   :group 'help)
+
+;; with a little help from Helm
+(defcustom help-mode-prefix-key "C-h M-h"
+  "`help-mode-map' prefix key for invocation from other buffers."
+  :version "30.1"
+  :type '(choice (string :tag "Key") (const :tag "no binding"))
+  :set (lambda (var key)
+         (when (and (boundp var) (symbol-value var))
+           (define-key (current-global-map)
+                       (read-kbd-macro (symbol-value var)) nil))
+         (when key
+           (define-key (current-global-map)
+                       (read-kbd-macro key)
+                       help-mode-map))
+         (set var key))
+  :group 'help)
 \f
 ;; Button types used by help
 
@@ -763,7 +794,127 @@ help-xref-on-pp
 
 ;;;###autoload
 (define-obsolete-function-alias 'help-xref-interned #'describe-symbol "25.1")
+\f
+;; commands from special-mode wrapped to work on help-mode only
+
+(defun help-quit-window ()
+  "As `quit-window' but works only on *Help* buffer."
+  (interactive)
+  (let ((help-window (get-buffer-window (help-buffer))))
+    (unless (window-live-p help-window)
+      (user-error "Help buffer is not currently visible."))
+    (with-selected-window help-window
+      (quit-window nil help-window))))
+
+(defun help-describe-mode ()
+  "As `describe-mode' but for *Help* buffer only."
+  (interactive)
+  (let ((help-buffer (get-buffer (help-buffer))))
+    (unless (window-live-p (get-buffer-window help-buffer))
+      (user-error "Help buffer is not currently visible."))
+    (describe-mode help-buffer)))
+
+(defun help-beginning-of-buffer ()
+  "As `help-beginning-of-buffer' but for *Help* buffer only."
+  (interactive)
+  (let ((help-window (get-buffer-window (help-buffer))))
+    (unless (window-live-p help-window)
+      (user-error "Help buffer is not currently visible."))
+    (with-selected-window help-window
+      (goto-char (point-min)))))
+
+(defun help-end-of-buffer ()
+  "As `help-end-of-buffer' but for *Help* buffer only."
+  (interactive)
+  (let ((help-window (get-buffer-window (help-buffer))))
+    (unless (window-live-p help-window)
+      (user-error "Help buffer is not currently visible."))
+    (with-selected-window help-window
+      (goto-char (point-max)))))
+\f
+;; from files.el, for completeness and to eliminate potential confusion
 
+(defun help-revert-buffer ()
+  "As `revert-buffer', but act on help buffer specifically."
+  (interactive)
+  (let ((help-window (get-buffer-window (help-buffer))))
+    (unless (window-live-p help-window)
+      (user-error "Help buffer is not currently visible."))
+    (with-selected-window help-window
+      (call-interactively #'revert-buffer))))
+\f
+;; Commands from button.el wrapped to work on help-mode only
+
+(defun help-forward-button ()
+  (interactive)
+  (let ((help-window (get-buffer-window (help-buffer))))
+    (unless (window-live-p help-window)
+      (user-error "Help buffer is not currently visible."))
+    (with-selected-window help-window
+      (forward-button 1))))
+
+(defun help-backward-button ()
+  (interactive)
+  (let ((help-window (get-buffer-window (help-buffer))))
+    (unless (window-live-p help-window)
+      (user-error "Help buffer is not currently visible."))
+    (with-selected-window help-window
+      (backward-button 1))))
+
+(defun help-button-describe ()
+  (interactive)
+  (let ((help-window (get-buffer-window (help-buffer))))
+    (unless (window-live-p help-window)
+      (user-error "Help buffer is not currently visible."))
+    (with-selected-window help-window
+      (button-describe))))
+
+(defun help-push-button ()
+  (interactive)
+  (let ((help-window (get-buffer-window (help-buffer))))
+    (unless (window-live-p help-window)
+      (error "Help buffer is not currently visible."))
+    (with-selected-window help-window
+      (push-button))))
+\f
+;; Commands from window.el wrapped to work on help-mode only
+
+(defun help-scroll-up-command (&optional arg)
+  "As `scroll-up-command' but works only on *Help* buffer."
+  (interactive "^P")
+  (let ((help-window (get-buffer-window (help-buffer))))
+    (unless (window-live-p help-window)
+      (error "Help buffer is not currently visible."))
+    (with-selected-window help-window
+      (scroll-up-command arg))))
+
+(defun help-scroll-down-command (&optional arg)
+  "As `scroll-down-command' but works only on *Help* buffer."
+  (interactive "^P")
+  (let ((help-window (get-buffer-window (help-buffer))))
+    (unless (window-live-p help-window)
+      (user-error "Help buffer is not currently visible."))
+    (with-selected-window help-window
+      (scroll-down-command arg))))
+
+\f
+
+(defvar help-jump nil)
+(defun help-jump ()
+  "Jump to and from *Help* window."
+  (interactive)
+  (let ((help-window (get-buffer-window (help-buffer)))
+        (current-window (selected-window)))
+    (cond
+     ((eq help-window current-window)
+      (unless help-jump
+        (user-error "No previously selected window to jump to."))
+      (select-window help-jump))
+     (t
+      (unless (window-live-p help-window)
+        (user-error "Help buffer is not currently visible."))
+      (setq help-jump current-window)
+      (select-window help-window)))))
 \f
 ;; Navigation/hyperlinking with xrefs
 
@@ -810,25 +961,37 @@ help-xref-go-forward
 (defun help-go-back ()
   "Go back to previous topic in this help buffer."
   (interactive)
-  (if help-xref-stack
-      (help-xref-go-back (current-buffer))
-    (user-error "No previous help buffer")))
+  (let ((help-buffer (get-buffer (help-buffer))))
+    (unless (window-live-p (get-buffer-window help-buffer))
+      (user-error "Help buffer is not currently visible."))
+    (with-current-buffer help-buffer
+      (if help-xref-stack
+          (help-xref-go-back (current-buffer))
+        (user-error "No previous help buffer")))))
 
 (defun help-go-forward ()
   "Go to the next topic in this help buffer."
   (interactive)
-  (if help-xref-forward-stack
-      (help-xref-go-forward (current-buffer))
-    (user-error "No next help buffer")))
+  (let ((help-buffer (get-buffer (help-buffer))))
+    (unless (window-live-p (get-buffer-window help-buffer))
+      (user-error "Help buffer is not currently visible."))
+    (with-current-buffer help-buffer
+      (if help-xref-forward-stack
+          (help-xref-go-forward (current-buffer))
+        (user-error "No next help buffer")))))
 
 (defun help-goto-next-page ()
   "Go to the next page (if any) in the current buffer.
 The help buffers are divided into \"pages\" by the ^L character."
   (interactive nil help-mode)
-  (push-mark)
-  (forward-page)
-  (unless (eobp)
-    (forward-line 1)))
+  (let ((help-window (get-buffer-window (help-buffer))))
+    (unless (window-live-p help-window)
+      (user-error "Help buffer is not currently visible."))
+    (with-selected-window help-window
+      (push-mark)
+      (forward-page)
+      (unless (eobp)
+        (forward-line 1)))))
 
 (defun help-goto-previous-page ()
   "Go to the previous page (if any) in the current buffer.
@@ -836,47 +999,68 @@ help-goto-previous-page
 
 The help buffers are divided into \"pages\" by the ^L character."
   (interactive nil help-mode)
-  (push-mark)
-  (backward-page (if (looking-back "\f\n" (- (point) 5)) 2 1))
-  (unless (bobp)
-    (forward-line 1)))
+  (let ((help-window (get-buffer-window (help-buffer))))
+    (unless (window-live-p help-window)
+      (user-error "Help buffer is not currently visible."))
+    (with-selected-window help-window
+      (push-mark)
+      (backward-page (if (looking-back "\f\n" (- (point) 5)) 2 1))
+      (unless (bobp)
+        (forward-line 1)))))
 
 (defun help-view-source ()
   "View the source of the current help item."
   (interactive nil help-mode)
-  (unless (plist-get help-mode--current-data :file)
-    (error "Source file for the current help item is not defined"))
-  (help-function-def--button-function
-   (plist-get help-mode--current-data :symbol)
-   (plist-get help-mode--current-data :file)
-   (plist-get help-mode--current-data :type)))
+  (let ((help-buffer (get-buffer (help-buffer))))
+    (unless (window-live-p (get-buffer-window help-buffer))
+      (user-error "Help buffer is not currently visible."))
+    (with-current-buffer help-buffer
+      (unless (plist-get help-mode--current-data :file)
+        (error "Source file for the current help item is not defined"))
+      (help-function-def--button-function
+       (plist-get help-mode--current-data :symbol)
+       (plist-get help-mode--current-data :file)
+       (plist-get help-mode--current-data :type)))))
 
 (defun help-goto-info ()
   "View the *info* node of the current help item."
   (interactive nil help-mode)
-  (unless help-mode--current-data
-    (error "No symbol to look up in the current buffer"))
-  (info-lookup-symbol (plist-get help-mode--current-data :symbol)
-                      'emacs-lisp-mode
-                      help-window-keep-selected))
+  (let ((help-buffer (get-buffer (help-buffer))))
+    (unless (window-live-p (get-buffer-window help-buffer))
+      (user-error "Help buffer is not currently visible."))
+    (with-current-buffer help-buffer
+      (unless help-mode--current-data
+        (error "No symbol to look up in the current buffer"))
+      (with-selected-window (get-buffer-window help-buffer)
+        (info-lookup-symbol (plist-get help-mode--current-data :symbol)
+                            'emacs-lisp-mode
+                            help-window-keep-selected)))))
 
 (defun help-goto-lispref-info ()
   "View the Emacs Lisp manual *info* node of the current help item."
   (interactive nil help-mode)
-  (unless help-mode--current-data
-    (error "No symbol to look up in the current buffer"))
-  (info-lookup-symbol (plist-get help-mode--current-data :symbol)
-                      'emacs-lisp-only))
+  (let ((help-buffer (get-buffer (help-buffer))))
+    (unless (window-live-p (get-buffer-window help-buffer))
+      (user-error "Help buffer is not currently visible."))
+    (with-current-buffer help-buffer
+      (unless help-mode--current-data
+        (error "No symbol to look up in the current buffer"))
+      (info-lookup-symbol (plist-get help-mode--current-data :symbol)
+                          'emacs-lisp-only))))
 
 (defun help-customize ()
   "Customize variable or face whose doc string is shown in the current buffer."
   (interactive nil help-mode)
-  (let ((sym (plist-get help-mode--current-data :symbol)))
-    (unless (or (boundp sym) (facep sym))
-      (user-error "No variable or face to customize"))
-    (cond
-     ((boundp sym) (customize-variable sym))
-     ((facep sym) (customize-face sym)))))
+  (let ((help-buffer (get-buffer (help-buffer))))
+    (unless (window-live-p (get-buffer-window help-buffer))
+      (user-error "Help buffer is not currently visible."))
+    (with-current-buffer help-buffer
+      (let ((sym (plist-get help-mode--current-data :symbol)))
+        (unless (or (boundp sym) (facep sym))
+          (user-error "No variable or face to customize"))
+        (cond
+         ((boundp sym) (customize-variable sym))
+         ((facep sym) (customize-face sym)))))))
 
 (defun help-do-xref (_pos function args)
   "Call the help cross-reference function FUNCTION with args ARGS.
diff --git a/lisp/info.el b/lisp/info.el
index 035dff66e75..dcc6ed667d8 100644
--- a/lisp/info.el
+++ b/lisp/info.el
@@ -819,6 +819,22 @@ info-standalone
 	       (save-buffers-kill-emacs)))
     (info)))
 \f
+(defvar Info-jump nil)
+(defun Info-jump ()
+  "Jump to and from *info* window."
+  (interactive)
+  (let ((info-window (get-buffer-window "*info*"))
+        (current-window (selected-window)))
+    (cond
+     ((eq info-window (selected-window))
+      (unless Info-jump
+        (error "No previously selected window to jump to."))
+      (select-window Info-jump))
+     (t
+      (when (window-live-p info-window)
+        (setq Info-jump current-window)
+        (select-window info-window))))))
+\f
 ;; See if the accessible portion of the buffer begins with a node
 ;; delimiter, and the node header line which follows matches REGEXP.
 ;; Typically, this test will be followed by a loop that examines the
@@ -831,12 +847,12 @@ info-standalone
 ;; The return value is the value of point at the beginning of matching
 ;; REGEXP, if the function succeeds, nil otherwise.
 (defun Info-node-at-bob-matching (regexp)
-  (and (bobp)				; are we at beginning of buffer?
-       (looking-at "\^_")		; does it begin with node delimiter?
+  (and (bobp)                     ; are we at beginning of buffer?
+       (looking-at "\^_")         ; does it begin with node delimiter?
        (let (beg)
 	 (forward-line 1)
 	 (setq beg (point))
-	 (forward-line 1)		; does the line after delimiter match REGEXP?
+	 (forward-line 1) ; does the line after delimiter match REGEXP?
 	 (re-search-backward regexp beg t))))
 
 (defun Info-find-file (filename &optional noerror no-pop-to-dir)
@@ -2273,85 +2289,108 @@ Info-next
   "Go to the \"next\" node, staying on the same hierarchical level.
 This command doesn't descend into sub-nodes, like \\<Info-mode-map>\\[Info-forward-node] does."
   (interactive nil Info-mode)
-  ;; In case another window is currently selected
-  (save-window-excursion
-    (or (derived-mode-p 'Info-mode) (switch-to-buffer "*info*"))
-    (Info-goto-node (Info-extract-pointer "next"))))
+  (let ((info-window (get-buffer-window "*info*")))
+    (unless (window-live-p info-window)
+      (user-error "There is no visible Info buffer."))
+    ;; In case another window is currently selected
+    (save-window-excursion
+      (or (derived-mode-p 'Info-mode) (switch-to-buffer "*info*"))
+      (Info-goto-node (Info-extract-pointer "next")))))
 
 (defun Info-prev ()
   "Go to the \"previous\" node, staying on the same hierarchical level.
 This command doesn't go up to the parent node, like \\<Info-mode-map>\\[Info-backward-node] does."
   (interactive nil Info-mode)
-  ;; In case another window is currently selected
-  (save-window-excursion
-    (or (derived-mode-p 'Info-mode) (switch-to-buffer "*info*"))
-    (Info-goto-node (Info-extract-pointer "prev[ious]*" "previous"))))
+  (let ((info-window (get-buffer-window "*info*")))
+    (unless (window-live-p info-window)
+      (user-error "There is no visible Info buffer."))
+    ;; In case another window is currently selected
+    (save-window-excursion
+      (or (derived-mode-p 'Info-mode) (switch-to-buffer "*info*"))
+      (Info-goto-node (Info-extract-pointer "prev[ious]*" "previous"))
+      ;; for some reason my Emacs does not update correctly info buffer after
+      ;; going back to a previous node, reverting buffer fixes it
+      (revert-buffer t t t))))
 
 (defun Info-up (&optional same-file)
   "Go to the superior node of this node.
 If SAME-FILE is non-nil, do not move to a different Info file."
   (interactive nil Info-mode)
-  ;; In case another window is currently selected
-  (save-window-excursion
-    (or (derived-mode-p 'Info-mode) (switch-to-buffer "*info*"))
-    (let ((old-node Info-current-node)
-	  (old-file Info-current-file)
-	  (node (Info-extract-pointer "up")) p)
-      (and same-file
-	   (string-match "^(" node)
-	   (error "Up node is in another Info file"))
-      (Info-goto-node node)
-      (setq p (point))
-      (goto-char (point-min))
-      (if (and (stringp old-file)
-	       (search-forward "\n* Menu:" nil t)
-	       (re-search-forward
-		(if (string-equal old-node "Top")
-		    (concat "\n\\*[^:]+: +(" (file-name-nondirectory old-file) ")")
-		  (concat "\n\\* +\\(" (regexp-quote old-node)
-			  ":\\|[^:]+: +" (regexp-quote old-node) "\\)"))
-		nil t))
-	  (progn (beginning-of-line) (if (looking-at "^\\* ") (forward-char 2)))
-	(goto-char p)
-	(Info-restore-point Info-history))))
-  ;; If scroll-conservatively is non-zero and less than 101, display
-  ;; as much of the superior node above the target line as possible.
-  (when (< 0 scroll-conservatively 101)
-    (recenter)))
+  (let ((info-window (get-buffer-window "*info*")))
+    (unless (window-live-p info-window)
+      (user-error "There is no visible Info buffer."))
+    (with-selected-window info-window
+      ;; In case another window is currently selected
+      (save-window-excursion
+        (or (derived-mode-p 'Info-mode) (switch-to-buffer "*info*"))
+        (let ((old-node Info-current-node)
+              (old-file Info-current-file)
+              (node (Info-extract-pointer "up")) p)
+          (and same-file
+               (string-match "^(" node)
+               (error "Up node is in another Info file"))
+          (Info-goto-node node)
+          (setq p (point))
+          (goto-char (point-min))
+          (if (and (stringp old-file)
+                   (search-forward "\n* Menu:" nil t)
+                   (re-search-forward
+                    (if (string-equal old-node "Top")
+                        (concat "\n\\*[^:]+: +(" (file-name-nondirectory old-file) ")")
+                      (concat "\n\\* +\\(" (regexp-quote old-node)
+                              ":\\|[^:]+: +" (regexp-quote old-node) "\\)"))
+                    nil t))
+              (progn (beginning-of-line) (if (looking-at "^\\* ") (forward-char 2)))
+            (goto-char p)
+            (Info-restore-point Info-history)))
+        ;; If scroll-conservatively is non-zero and less than 101, display
+        ;; as much of the superior node above the target line as possible.
+        ;; (when (< 0 scroll-conservatively 101) (recenter))
+        ;; for some reason, in my Emacs, this is the only obe that actually
+        ;; displays correctly, recentering leavs last line at the top
+        (revert-buffer t t t)))))
 
 (defun Info-history-back ()
   "Go back in the history to the last node visited."
   (interactive nil Info-mode)
-  (or Info-history
-      (user-error "This is the first Info node you looked at"))
-  (let ((history-forward
-	 (cons (list Info-current-file Info-current-node (point))
-	       Info-history-forward))
-	filename nodename opoint)
-    (setq filename (car (car Info-history)))
-    (setq nodename (car (cdr (car Info-history))))
-    (setq opoint (car (cdr (cdr (car Info-history)))))
-    (setq Info-history (cdr Info-history))
-    (Info-find-node filename nodename)
-    (setq Info-history (cdr Info-history))
-    (setq Info-history-forward history-forward)
-    (goto-char opoint)))
+  (let ((info-window (get-buffer-window "*info*")))
+    (unless (window-live-p info-window)
+      (user-error "There is no visible Info buffer."))
+    (with-selected-window info-window
+      (or Info-history
+          (user-error "This is the first Info node you looked at"))
+      (let ((history-forward
+             (cons (list Info-current-file Info-current-node (point))
+                   Info-history-forward))
+            filename nodename opoint)
+        (setq filename (car (car Info-history)))
+        (setq nodename (car (cdr (car Info-history))))
+        (setq opoint (car (cdr (cdr (car Info-history)))))
+        (setq Info-history (cdr Info-history))
+        (Info-find-node filename nodename)
+        (setq Info-history (cdr Info-history))
+        (setq Info-history-forward history-forward)
+        (goto-char opoint)))))
 
 (defalias 'Info-last 'Info-history-back)
 
 (defun Info-history-forward ()
   "Go forward in the history of visited nodes."
   (interactive nil Info-mode)
-  (or Info-history-forward
-      (user-error "This is the last Info node you looked at"))
-  (let ((history-forward (cdr Info-history-forward))
-	filename nodename opoint)
-    (setq filename (car (car Info-history-forward)))
-    (setq nodename (car (cdr (car Info-history-forward))))
-    (setq opoint (car (cdr (cdr (car Info-history-forward)))))
-    (Info-find-node filename nodename)
-    (setq Info-history-forward history-forward)
-    (goto-char opoint)))
+  (let ((info-window (get-buffer-window "*info*")))
+    (unless (window-live-p info-window)
+      (user-error "There is no visible Info buffer."))
+    (with-selected-window info-window
+      (or Info-history-forward
+          (user-error "This is the last Info node you looked at"))
+      (let ((history-forward (cdr Info-history-forward))
+            filename nodename opoint)
+        (setq filename (car (car Info-history-forward)))
+        (setq nodename (car (cdr (car Info-history-forward))))
+        (setq opoint (car (cdr (cdr (car Info-history-forward)))))
+        (Info-find-node filename nodename)
+        (setq Info-history-forward history-forward)
+        (goto-char opoint)))))
 \f
 (add-to-list 'Info-virtual-files
 	     '("\\`dir\\'"
@@ -2377,7 +2416,11 @@ Info-directory-find-node
 (defun Info-directory ()
   "Go to the Info directory node."
   (interactive)
-  (Info-find-node "dir" "top"))
+  (let ((info-window (get-buffer-window "*info*")))
+    (unless (window-live-p info-window)
+      (user-error "There is no visible Info buffer."))
+    (with-selected-window info-window
+      (Info-find-node "dir" "top"))))
 \f
 (add-to-list 'Info-virtual-files
 	     '("\\`\\*History\\*\\'"
@@ -2416,9 +2459,13 @@ Info-history-find-node
 (defun Info-history ()
   "Go to a node with a menu of visited nodes."
   (interactive nil Info-mode)
-  (Info-find-node "*History*" "Top")
-  (Info-next-reference)
-  (Info-next-reference))
+  (let ((info-window (get-buffer-window "*info*")))
+    (unless (window-live-p info-window)
+      (user-error "There is no visible Info buffer."))
+    (with-selected-window info-window
+      (Info-find-node "*History*" "Top")
+      (Info-next-reference)
+      (Info-next-reference))))
 \f
 (add-to-list 'Info-virtual-nodes
 	     '("\\`\\*TOC\\*\\'"
@@ -2453,12 +2500,16 @@ Info-toc
   "Go to a node with table of contents of the current Info file.
 Table of contents is created from the tree structure of menus."
   (interactive nil Info-mode)
-  (Info-find-node Info-current-file "*TOC*")
-  (let ((prev-node (nth 1 (car Info-history))) p)
-    (goto-char (point-min))
-    (if (setq p (search-forward (concat "*Note " prev-node ":") nil t))
-	(setq p (- p (length prev-node) 2)))
-    (goto-char (or p (point-min)))))
+  (let ((info-window (get-buffer-window "*info*")))
+    (unless (window-live-p info-window)
+      (user-error "There is no visible Info buffer."))
+    (with-selected-window info-window
+      (Info-find-node Info-current-file "*TOC*")
+      (let ((prev-node (nth 1 (car Info-history))) p)
+        (goto-char (point-min))
+        (if (setq p (search-forward (concat "*Note " prev-node ":") nil t))
+            (setq p (- p (length prev-node) 2)))
+        (goto-char (or p (point-min)))))))
 
 (defun Info-toc-insert (nodes node-list level curr-file)
   "Insert table of contents with references to nodes."
@@ -2798,38 +2849,45 @@ Info-menu
 new buffer."
   (interactive
    (let (;; If point is within a menu item, use that item as the default
-	 (default nil)
-	 (p (point))
-	 beg
-	 (case-fold-search t))
+         (default nil)
+         (p (point))
+         beg
+         (case-fold-search t)
+         (info-window (get-buffer-window "*info*")))
+     (unless (window-live-p info-window)
+       (user-error "There is no visible Info buffer."))
+     (if (not (eq (selected-window) info-window))
+         (Info-jump)
+       (setq Info-jump nil))
      (save-excursion
        (goto-char (point-min))
        (if (not (search-forward "\n* menu:" nil t))
-	   (user-error "No menu in this node"))
+           (user-error "No menu in this node"))
        (setq beg (point))
        (and (< (point) p)
-	    (save-excursion
-	      (goto-char p)
-	      (end-of-line)
-	      (if (re-search-backward (concat "\n\\* +\\("
-					      Info-menu-entry-name-re
-					      "\\):")
+            (save-excursion
+              (goto-char p)
+              (end-of-line)
+              (if (re-search-backward (concat "\n\\* +\\("
+                                              Info-menu-entry-name-re
+                                              "\\):")
                                       beg t)
-		  (setq default (match-string-no-properties 1))))))
+                  (setq default (match-string-no-properties 1))))))
      (let ((item nil))
        (while (null item)
-	 (setq item (let ((completion-ignore-case t)
-			  (Info-complete-menu-buffer (current-buffer)))
-		      (completing-read (format-prompt "Menu item" default)
-				       #'Info-complete-menu-item nil t nil nil
+         (setq item (let ((completion-ignore-case t)
+                          (Info-complete-menu-buffer (current-buffer)))
+                      (completing-read (format-prompt "Menu item" default)
+                                       #'Info-complete-menu-item nil t nil nil
                                        default))))
        (list item current-prefix-arg)))
    Info-mode)
   ;; there is a problem here in that if several menu items have the same
   ;; name you can only go to the node of the first with this command.
   (Info-goto-node (Info-extract-menu-item menu-item)
-		  (and fork
-		       (if (stringp fork) fork menu-item))))
+                  (and fork
+                       (if (stringp fork) fork menu-item)))
+  (when Info-jump (Info-jump)))
 
 (defun Info-extract-menu-item (menu-item)
   (setq menu-item (regexp-quote menu-item))
@@ -2869,32 +2927,44 @@ Info-nth-menu-item
   "Go to the node of the Nth menu item.
 N is the digit argument used to invoke this command."
   (interactive nil Info-mode)
-  (Info-goto-node
-   (Info-extract-menu-counting
-    (- (aref (this-command-keys) (1- (length (this-command-keys)))) ?0))))
+  (let ((info-window (get-buffer-window "*info*")))
+    (unless (window-live-p info-window)
+      (user-error "There is no visible Info buffer."))
+    (with-selected-window info-window
+      (Info-goto-node
+       (Info-extract-menu-counting
+        (- (aref (this-command-keys) (1- (length (this-command-keys)))) ?0))))))
 
 (defun Info-top-node ()
   "Go to the Top node of this file."
   (interactive nil Info-mode)
-  (Info-goto-node "Top"))
+  (let ((info-window (get-buffer-window "*info*")))
+    (unless (window-live-p info-window)
+      (user-error "There is no visible Info buffer."))
+    (with-selected-window info-window
+      (Info-goto-node "Top"))))
 
 (defun Info-final-node ()
   "Go to the final node in this file."
   (interactive nil Info-mode)
-  (Info-goto-node "Top")
-  (let ((Info-history nil)
-	(case-fold-search t))
-    ;; Go to the last node in the menu of Top.  But don't delve into
-    ;; detailed node listings.
-    (Info-goto-node (Info-extract-menu-counting nil t))
-    ;; If the last node in the menu is not last in pointer structure,
-    ;; move forward (but not down- or upward - see bug#1116) until we
-    ;; can't go any farther.
-    (while (Info-forward-node t t t) nil)
-    ;; Then keep moving down to last subnode, unless we reach an index.
-    (while (and (not (Info-index-node))
-		(save-excursion (search-forward "\n* Menu:" nil t)))
-      (Info-goto-node (Info-extract-menu-counting nil)))))
+  (let ((info-window (get-buffer-window "*info*")))
+    (unless (window-live-p info-window)
+      (user-error "There is no visible Info buffer."))
+    (with-selected-window info-window
+      (Info-goto-node "Top")
+      (let ((Info-history nil)
+            (case-fold-search t))
+        ;; Go to the last node in the menu of Top.  But don't delve into
+        ;; detailed node listings.
+        (Info-goto-node (Info-extract-menu-counting nil t))
+        ;; If the last node in the menu is not last in pointer structure,
+        ;; move forward (but not down- or upward - see bug#1116) until we
+        ;; can't go any farther.
+        (while (Info-forward-node t t t) nil)
+        ;; Then keep moving down to last subnode, unless we reach an index.
+        (while (and (not (Info-index-node))
+                    (save-excursion (search-forward "\n* Menu:" nil t)))
+          (Info-goto-node (Info-extract-menu-counting nil)))))))
 
 (defun Info-forward-node (&optional not-down not-up no-error)
   "Go forward one node, considering all nodes as forming one sequence.
@@ -2905,66 +2975,76 @@ Info-forward-node
 NOT-UP non-nil means don't go to parent nodes, and NO-ERROR non-nil means
 don't signal a user-error if there's no node to go to."
   (interactive nil Info-mode)
-  (goto-char (point-min))
-  (forward-line 1)
-  (let ((case-fold-search t))
-    ;; three possibilities, in order of priority:
-    ;;     1. next node is in a menu in this node (but not in an index)
-    ;;     2. next node is next at same level
-    ;;     3. next node is up and next
-    (cond ((and (not not-down)
-		(save-excursion (search-forward "\n* menu:" nil t))
-		(not (Info-index-node)))
-	   (Info-goto-node (Info-extract-menu-counting 1))
-	   t)
-	  ((save-excursion (search-backward "next:" nil t))
-	   (Info-next)
-	   t)
-	  ((and (not not-up)
-		(save-excursion (search-backward "up:" nil t))
-		;; Use string-equal, not equal, to ignore text props.
-		(not (string-equal (downcase (Info-extract-pointer "up"))
-				   "top")))
-	   (let ((old-node Info-current-node))
-	     (Info-up)
-	     (let ((old-history Info-history)
-		   success)
-	       (unwind-protect
-		   (setq success (Info-forward-node t nil no-error))
-		 (or success (Info-goto-node old-node)))
-	       (if Info-history-skip-intermediate-nodes
-		   (setq Info-history old-history)))))
-	  (no-error nil)
-	  (t (user-error "No pointer forward from this node")))))
+  (let ((info-window (get-buffer-window "*info*")))
+    (unless (window-live-p info-window)
+      (user-error "There is no visible Info buffer."))
+    (with-selected-window info-window
+      (goto-char (point-min))
+      (forward-line 1)
+      (let ((case-fold-search t))
+        ;; three possibilities, in order of priority:
+        ;;     1. next node is in a menu in this node (but not in an index)
+        ;;     2. next node is next at same level
+        ;;     3. next node is up and next
+        (cond ((and (not not-down)
+                    (save-excursion (search-forward "\n* menu:" nil t))
+                    (not (Info-index-node)))
+               (Info-goto-node (Info-extract-menu-counting 1))
+               t)
+              ((save-excursion (search-backward "next:" nil t))
+               (Info-next)
+               t)
+              ((and (not not-up)
+                    (save-excursion (search-backward "up:" nil t))
+                    ;; Use string-equal, not equal, to ignore text props.
+                    (not (string-equal (downcase (Info-extract-pointer "up"))
+                                       "top")))
+               (let ((old-node Info-current-node))
+                 (Info-up)
+                 (let ((old-history Info-history)
+                       success)
+                   (unwind-protect
+                       (setq success (Info-forward-node t nil no-error))
+                     (or success (Info-goto-node old-node)))
+                   (if Info-history-skip-intermediate-nodes
+                       (setq Info-history old-history)))))
+              (no-error nil)
+              (t (user-error "No pointer forward from this node")))))))
 
 (defun Info-backward-node ()
   "Go backward one node, considering all nodes as forming one sequence.
 If the current node has a \"previous\" node, go to it, descending into its
 last sub-node, if any; otherwise go \"up\" to the parent node."
   (interactive nil Info-mode)
-  (let ((prevnode (Info-extract-pointer "prev[ious]*" t))
-	(upnode (Info-extract-pointer "up" t))
-	(case-fold-search t))
-    (cond ((and upnode (string-search "(" upnode))
-	   (user-error "First node in file"))
-	  ((and upnode (or (null prevnode)
-			   ;; Use string-equal, not equal,
-			   ;; to ignore text properties.
-			   (string-equal (downcase prevnode)
-					 (downcase upnode))))
-	   (Info-up))
-	  (prevnode
-	   ;; If we move back at the same level,
-	   ;; go down to find the last subnode*.
-	   (Info-prev)
-	   (let ((old-history Info-history))
-	     (while (and (not (Info-index-node))
-			 (save-excursion (search-forward "\n* Menu:" nil t)))
-	       (Info-goto-node (Info-extract-menu-counting nil)))
-	     (if Info-history-skip-intermediate-nodes
-		 (setq Info-history old-history))))
-	  (t
-	   (user-error "No pointer backward from this node")))))
+  (let ((info-window (get-buffer-window "*info*")))
+    (unless (window-live-p info-window)
+      (user-error "There is no visible Info buffer."))
+    (with-selected-window info-window
+      (let ((prevnode (Info-extract-pointer "prev[ious]*" t))
+            (upnode (Info-extract-pointer "up" t))
+            (case-fold-search t))
+        (cond ((and upnode (string-search "(" upnode))
+               (user-error "First node in file"))
+              ((and upnode (or (null prevnode)
+                               ;; Use string-equal, not equal,
+                               ;; to ignore text properties.
+                               (string-equal (downcase prevnode)
+                                             (downcase upnode))))
+               (Info-up))
+              (prevnode
+               ;; If we move back at the same level,
+               ;; go down to find the last subnode*.
+               (Info-prev)
+               (let ((old-history Info-history))
+                 (while (and (not (Info-index-node))
+                             (save-excursion (search-forward "\n* Menu:" nil t)))
+                   (Info-goto-node (Info-extract-menu-counting nil)))
+                 (if Info-history-skip-intermediate-nodes
+                     (setq Info-history old-history))))
+              (t
+               (user-error "No pointer backward from this node")))
+        ;; Emacs sometimes display just the very last line
+        (goto-char (point-min))))))
 
 (define-obsolete-function-alias 'Info-exit #'quit-window "27.1")
 
@@ -2972,31 +3052,39 @@ Info-next-menu-item
   "Go to the node of the next menu item."
   (interactive nil Info-mode)
   ;; Bind this in case the user sets it to nil.
-  (let* ((case-fold-search t)
-	 (node
-	  (save-excursion
-	    (forward-line -1)
-	    (search-forward "\n* menu:" nil t)
-	    (and (search-forward "\n* " nil t)
-		 (Info-extract-menu-node-name)))))
-    (if node (Info-goto-node node)
-      (user-error "No more items in menu"))))
+  (let ((info-window (get-buffer-window "*info*")))
+    (unless (window-live-p info-window)
+      (user-error "There is no visible Info buffer."))
+    (with-selected-window info-window
+      (let* ((case-fold-search t)
+             (node
+              (save-excursion
+                (forward-line -1)
+                (search-forward "\n* menu:" nil t)
+                (and (search-forward "\n* " nil t)
+                     (Info-extract-menu-node-name)))))
+        (if node (Info-goto-node node)
+          (user-error "No more items in menu"))))))
 
 (defun Info-last-menu-item ()
   "Go to the node of the previous menu item."
   (interactive nil Info-mode)
-  (save-excursion
-    (forward-line 1)
-    ;; Bind this in case the user sets it to nil.
-    (let* ((case-fold-search t)
-	   (beg (save-excursion
-		  (and (search-backward "\n* menu:" nil t)
-		       (point)))))
-      (or (and beg (search-backward "\n* " beg t))
-	  (user-error "No previous items in menu")))
-    (Info-goto-node (save-excursion
-		      (goto-char (match-end 0))
-		      (Info-extract-menu-node-name)))))
+  (let ((info-window (get-buffer-window "*info*")))
+    (unless (window-live-p info-window)
+      (user-error "There is no visible Info buffer."))
+    (with-selected-window info-window
+      (save-excursion
+        (forward-line 1)
+        ;; Bind this in case the user sets it to nil.
+        (let* ((case-fold-search t)
+               (beg (save-excursion
+                      (and (search-backward "\n* menu:" nil t)
+                           (point)))))
+          (or (and beg (search-backward "\n* " beg t))
+              (user-error "No previous items in menu")))
+        (Info-goto-node (save-excursion
+                          (goto-char (match-end 0))
+                          (Info-extract-menu-node-name)))))))
 
 (defmacro Info-no-error (&rest body)
   `(condition-case nil (progn ,@body t) (error nil)))
@@ -3004,61 +3092,69 @@ Info-no-error
 (defun Info-next-preorder ()
   "Go to the next subnode or the next node, or go up a level."
   (interactive nil Info-mode)
-  (cond ((Info-no-error (Info-next-menu-item)))
-	((Info-no-error (Info-next)))
-	((Info-no-error (Info-up t))
-	 ;; Since we have already gone thru all the items in this menu,
-	 ;; go up to the end of this node.
-	 (goto-char (point-max))
-	 ;; Since logically we are done with the node with that menu,
-	 ;; move on from it.  But don't add intermediate nodes
-	 ;; to the history on recursive calls.
-	 (let ((old-history Info-history))
-	   (Info-next-preorder)
-	   (if Info-history-skip-intermediate-nodes
-	       (setq Info-history old-history))))
-	(t
-	 (user-error "No more nodes"))))
+  (let ((info-window (get-buffer-window "*info*")))
+    (unless (window-live-p info-window)
+      (user-error "There is no visible Info buffer."))
+    (with-selected-window info-window
+      (cond ((Info-no-error (Info-next-menu-item)))
+            ((Info-no-error (Info-next)))
+            ((Info-no-error (Info-up t))
+             ;; Since we have already gone thru all the items in this menu,
+             ;; go up to the end of this node.
+             (goto-char (point-max))
+             ;; Since logically we are done with the node with that menu,
+             ;; move on from it.  But don't add intermediate nodes
+             ;; to the history on recursive calls.
+             (let ((old-history Info-history))
+               (Info-next-preorder)
+               (if Info-history-skip-intermediate-nodes
+                   (setq Info-history old-history))))
+            (t
+             (user-error "No more nodes"))))))
 
 (defun Info-last-preorder ()
   "Go to the last node, popping up a level if there is none."
   (interactive nil Info-mode)
-  (cond ((and Info-scroll-prefer-subnodes
-	      (Info-no-error
-	       (Info-last-menu-item)
-	       ;; If we go down a menu item, go to the end of the node
-	       ;; so we can scroll back through it.
-	       (goto-char (point-max))))
-	 ;; Keep going down, as long as there are nested menu nodes.
-	 (let ((old-history Info-history))
-	   (while (Info-no-error
-		   (Info-last-menu-item)
-		   ;; If we go down a menu item, go to the end of the node
-		   ;; so we can scroll back through it.
-		   (goto-char (point-max))))
-	   (if Info-history-skip-intermediate-nodes
-	       (setq Info-history old-history)))
-	 (recenter -1))
-	((and (Info-no-error (Info-extract-pointer "prev"))
-	      (not (equal (Info-extract-pointer "up")
-			  (Info-extract-pointer "prev"))))
-	 (Info-no-error (Info-prev))
-	 (goto-char (point-max))
-	 (let ((old-history Info-history))
-	   (while (Info-no-error
-		   (Info-last-menu-item)
-		   ;; If we go down a menu item, go to the end of the node
-		   ;; so we can scroll back through it.
-		   (goto-char (point-max))))
-	   (if Info-history-skip-intermediate-nodes
-	       (setq Info-history old-history)))
-	 (recenter -1))
-	((Info-no-error (Info-up t))
-	 (goto-char (point-min))
-	 (let ((case-fold-search t))
-	   (or (search-forward "\n* Menu:" nil t)
-	       (goto-char (point-max)))))
-	(t (user-error "No previous nodes"))))
+  (let ((info-window (get-buffer-window "*info*")))
+    (unless (window-live-p info-window)
+      (user-error "There is no visible Info buffer."))
+    (with-selected-window info-window
+      (cond ((and Info-scroll-prefer-subnodes
+                  (Info-no-error
+                   (Info-last-menu-item)
+                   ;; If we go down a menu item, go to the end of the node
+                   ;; so we can scroll back through it.
+                   (goto-char (point-max))))
+             ;; Keep going down, as long as there are nested menu nodes.
+             (let ((old-history Info-history))
+               (while (Info-no-error
+                       (Info-last-menu-item)
+                       ;; If we go down a menu item, go to the end of the node
+                       ;; so we can scroll back through it.
+                       (goto-char (point-max))))
+               (if Info-history-skip-intermediate-nodes
+                   (setq Info-history old-history)))
+             (recenter -1))
+            ((and (Info-no-error (Info-extract-pointer "prev"))
+                  (not (equal (Info-extract-pointer "up")
+                              (Info-extract-pointer "prev"))))
+             (Info-no-error (Info-prev))
+             (goto-char (point-max))
+             (let ((old-history Info-history))
+               (while (Info-no-error
+                       (Info-last-menu-item)
+                       ;; If we go down a menu item, go to the end of the node
+                       ;; so we can scroll back through it.
+                       (goto-char (point-max))))
+               (if Info-history-skip-intermediate-nodes
+                   (setq Info-history old-history)))
+             (recenter -1))
+            ((Info-no-error (Info-up t))
+             (goto-char (point-min))
+             (let ((case-fold-search t))
+               (or (search-forward "\n* Menu:" nil t)
+                   (goto-char (point-max)))))
+            (t (user-error "No previous nodes"))))))
 
 (defun Info-scroll-up ()
   "Scroll one screenful forward in Info, considering all nodes as one sequence.
@@ -3075,23 +3171,27 @@ Info-scroll-up
 in other ways.)"
 
   (interactive nil Info-mode)
-  (if (or (< (window-start) (point-min))
-	  (> (window-start) (point-max)))
-      (set-window-start (selected-window) (point)))
-  (let* ((case-fold-search t)
-	 (virtual-end (save-excursion
-			(goto-char (point-min))
-			(if (and Info-scroll-prefer-subnodes
-				 (search-forward "\n* Menu:" nil t))
-			    (point)
-			  (point-max)))))
-    (if (or (< virtual-end (window-start))
-	    (pos-visible-in-window-p virtual-end))
-	(cond
-	 (Info-scroll-prefer-subnodes (Info-next-preorder))
-	 ((Info-no-error (Info-goto-node (Info-extract-menu-counting 1))))
-	 (t (Info-next-preorder)))
-      (scroll-up))))
+  (let ((info-window (get-buffer-window "*info*")))
+    (unless (window-live-p info-window)
+      (user-error "There is no visible Info buffer."))
+    (with-selected-window info-window
+        (if (or (< (window-start) (point-min))
+                (> (window-start) (point-max)))
+            (set-window-start (selected-window) (point)))
+      (let* ((case-fold-search t)
+             (virtual-end (save-excursion
+                            (goto-char (point-min))
+                            (if (and Info-scroll-prefer-subnodes
+                                     (search-forward "\n* Menu:" nil t))
+                                (point)
+                              (point-max)))))
+        (if (or (< virtual-end (window-start))
+                (pos-visible-in-window-p virtual-end))
+            (cond
+             (Info-scroll-prefer-subnodes (Info-next-preorder))
+             ((Info-no-error (Info-goto-node (Info-extract-menu-counting 1))))
+             (t (Info-next-preorder)))
+          (scroll-up))))))
 
 (defun Info-mouse-scroll-up (e)
   "Scroll one screenful forward in Info, using the mouse.
@@ -3109,21 +3209,25 @@ Info-scroll-down
 beginning of a node, that goes to the previous node or back up to the
 parent node."
   (interactive nil Info-mode)
-  (if (or (< (window-start) (point-min))
-	  (> (window-start) (point-max)))
-      (set-window-start (selected-window) (point)))
-  (let* ((case-fold-search t)
-	 (current-point (point))
-	 (virtual-end
-	  (and Info-scroll-prefer-subnodes
-	       (save-excursion
-		 (setq current-point (line-beginning-position))
-		 (goto-char (point-min))
-		 (search-forward "\n* Menu:" current-point t)))))
-    (if (or virtual-end
-	    (pos-visible-in-window-p (point-min) nil t))
-	(Info-last-preorder)
-      (scroll-down))))
+  (let ((info-window (get-buffer-window "*info*")))
+    (unless (window-live-p info-window)
+      (user-error "There is no visible Info buffer."))
+    (with-selected-window info-window
+      (if (or (< (window-start) (point-min))
+              (> (window-start) (point-max)))
+          (set-window-start (selected-window) (point)))
+      (let* ((case-fold-search t)
+             (current-point (point))
+             (virtual-end
+              (and Info-scroll-prefer-subnodes
+                   (save-excursion
+                     (setq current-point (line-beginning-position))
+                     (goto-char (point-min))
+                     (search-forward "\n* Menu:" current-point t)))))
+        (if (or virtual-end
+                (pos-visible-in-window-p (point-min) nil t))
+            (Info-last-preorder)
+          (scroll-down))))))
 
 (defun Info-mouse-scroll-down (e)
   "Scroll one screenful backward in Info, using the mouse.
@@ -3175,55 +3279,63 @@ Info-next-reference
 If COUNT is non-nil (interactively with a prefix arg), jump over
 COUNT cross-references."
   (interactive "i\np" Info-mode)
-  (unless count
-    (setq count 1))
-  (if (< count 0)
-      (Info-prev-reference recur (- count))
-    (while (unless (zerop count) (setq count (1- count)))
-      (let ((pat "\\*note[ \n\t]+\\([^:]+\\):\\|^\\* .*:\\|[hf]t?tps?://")
-	    (old-pt (point))
-	    (case-fold-search t))
-	(or (eobp) (forward-char 1))
-	(or (Info-next-reference-or-link pat 'link)
-	    (progn
-	      (goto-char (point-min))
-	      (or (Info-next-reference-or-link pat 'link)
-		  (progn
-		    (goto-char old-pt)
-		    (user-error "No cross references in this node")))))
-	(if (looking-at "\\* Menu:")
-	    (if recur
-		(user-error "No cross references in this node")
-	      (Info-next-reference t))
-	  (if (looking-at "^\\* ")
-	      (forward-char 2)))))))
+  (let ((info-window (get-buffer-window "*info*")))
+    (unless (window-live-p info-window)
+      (user-error "There is no visible Info buffer."))
+    (with-selected-window info-window
+      (unless count
+        (setq count 1))
+      (if (< count 0)
+          (Info-prev-reference recur (- count))
+        (while (unless (zerop count) (setq count (1- count)))
+          (let ((pat "\\*note[ \n\t]+\\([^:]+\\):\\|^\\* .*:\\|[hf]t?tps?://")
+                (old-pt (point))
+                (case-fold-search t))
+            (or (eobp) (forward-char 1))
+            (or (Info-next-reference-or-link pat 'link)
+                (progn
+                  (goto-char (point-min))
+                  (or (Info-next-reference-or-link pat 'link)
+                      (progn
+                        (goto-char old-pt)
+                        (user-error "No cross references in this node")))))
+            (if (looking-at "\\* Menu:")
+                (if recur
+                    (user-error "No cross references in this node")
+                  (Info-next-reference t))
+              (if (looking-at "^\\* ")
+                  (forward-char 2)))))))))
 
 (defun Info-prev-reference (&optional recur count)
   "Move cursor to the previous cross-reference or menu item in the node.
 If COUNT is non-nil (interactively with a prefix arg), jump over
 COUNT cross-references."
   (interactive "i\np" Info-mode)
-  (unless count
-    (setq count 1))
-  (if (< count 0)
-      (Info-next-reference recur (- count))
-    (while (unless (zerop count) (setq count (1- count)))
-      (let ((pat "\\*note[ \n\t]+\\([^:]+\\):\\|^\\* .*:\\|[hf]t?tps?://")
-	    (old-pt (point))
-	    (case-fold-search t))
-	(or (Info-prev-reference-or-link pat 'link)
-	    (progn
-	      (goto-char (point-max))
-	      (or (Info-prev-reference-or-link pat 'link)
-		  (progn
-		    (goto-char old-pt)
-		    (user-error "No cross references in this node")))))
-	(if (looking-at "\\* Menu:")
-	    (if recur
-		(user-error "No cross references in this node")
-	      (Info-prev-reference t))
-	  (if (looking-at "^\\* ")
-	      (forward-char 2)))))))
+  (let ((info-window (get-buffer-window "*info*")))
+    (unless (window-live-p info-window)
+      (user-error "There is no visible Info buffer."))
+    (with-selected-window info-window
+      (unless count
+        (setq count 1))
+      (if (< count 0)
+          (Info-next-reference recur (- count))
+        (while (unless (zerop count) (setq count (1- count)))
+          (let ((pat "\\*note[ \n\t]+\\([^:]+\\):\\|^\\* .*:\\|[hf]t?tps?://")
+                (old-pt (point))
+                (case-fold-search t))
+            (or (Info-prev-reference-or-link pat 'link)
+                (progn
+                  (goto-char (point-max))
+                  (or (Info-prev-reference-or-link pat 'link)
+                      (progn
+                        (goto-char old-pt)
+                        (user-error "No cross references in this node")))))
+            (if (looking-at "\\* Menu:")
+                (if recur
+                    (user-error "No cross references in this node")
+                  (Info-prev-reference t))
+              (if (looking-at "^\\* ")
+                  (forward-char 2)))))))))
 \f
 (defun Info-index-nodes (&optional file)
   "Return a list of names of all index nodes in Info FILE.
@@ -3345,64 +3457,71 @@ Info-index
 Give an empty topic name to go to the Index node itself."
   (interactive
    (list
-    (let ((completion-ignore-case t)
-	  (Info-complete-menu-buffer (clone-buffer))
-	  (Info-complete-nodes (Info-index-nodes))
-	  (Info-history-list nil))
-      (info--ensure-not-in-directory-node)
-      (unwind-protect
-	  (with-current-buffer Info-complete-menu-buffer
-	    (Info-goto-index)
-	    (completing-read "Index topic: " #'Info-complete-menu-item))
-	(kill-buffer Info-complete-menu-buffer)))))
+    (let ((info-window (get-buffer-window "*info*")))
+      (unless (window-live-p info-window)
+        (user-error "There is no visible Info buffer."))
+      (if  (not (eq (selected-window) info-window))
+          (Info-jump)
+        (setq Info-jump nil))
+      (let ((completion-ignore-case t)
+            (Info-complete-menu-buffer (clone-buffer))
+            (Info-complete-nodes (Info-index-nodes))
+            (Info-history-list nil))
+        (info--ensure-not-in-directory-node)
+        (unwind-protect
+            (with-current-buffer Info-complete-menu-buffer
+              (Info-goto-index)
+              (completing-read "Index topic: " #'Info-complete-menu-item))
+          (kill-buffer Info-complete-menu-buffer))))))
   (info--ensure-not-in-directory-node)
   ;; Strip leading colon in topic; index format does not allow them.
   (if (and (stringp topic)
-	   (> (length topic) 0)
-	   (= (aref topic 0) ?:))
+           (> (length topic) 0)
+           (= (aref topic 0) ?:))
       (setq topic (substring topic 1)))
   (let ((orignode Info-current-node)
-	(pattern (format "\n\\* +\\([^\n]*\\(%s\\)[^\n]*\\):[ \t]+\\([^\n]*\\)\\.\\(?:[ \t\n]*(line +\\([0-9]+\\))\\)?"
-			 (regexp-quote topic)))
-	node (nodes (Info-index-nodes))
-	(ohist-list Info-history-list)
-	(case-fold-search t))
+        (pattern (format "\n\\* +\\([^\n]*\\(%s\\)[^\n]*\\):[ \t]+\\([^\n]*\\)\\.\\(?:[ \t\n]*(line +\\([0-9]+\\))\\)?"
+                         (regexp-quote topic)))
+        node (nodes (Info-index-nodes))
+        (ohist-list Info-history-list)
+        (case-fold-search t))
     (Info-goto-index)
     (or (equal topic "")
-	(let ((matches nil)
-	      (exact nil)
-	      ;; We bind Info-history to nil for internal node-switches so
-	      ;; that we don't put junk in the history.  In the first
-	      ;; Info-goto-index call, above, we do update the history
-	      ;; because that is what the user's previous node choice into it.
-	      (Info-history nil)
-	      found)
-	  (while
-	      (progn
-		(goto-char (point-min))
-		(while (re-search-forward pattern nil t)
-		  (let ((entry (match-string-no-properties 1))
-			(nodename (match-string-no-properties 3))
-			(line (string-to-number (concat "0" (match-string 4)))))
-		    (add-text-properties
-		     (- (match-beginning 2) (match-beginning 1))
-		     (- (match-end 2) (match-beginning 1))
-		     '(face info-index-match) entry)
-		    (push (list entry nodename Info-current-node line) matches)))
-		(setq nodes (cdr nodes) node (car nodes)))
-	    (Info-goto-node node))
-	  (or matches
-	      (progn
-		(Info-goto-node orignode)
-		(user-error "No `%s' in index" topic)))
-	  ;; Here it is a feature that assoc is case-sensitive.
-	  (while (setq found (assoc topic matches))
-	    (setq exact (cons found exact)
-		  matches (delq found matches)))
+        (let ((matches nil)
+              (exact nil)
+              ;; We bind Info-history to nil for internal node-switches so
+              ;; that we don't put junk in the history.  In the first
+              ;; Info-goto-index call, above, we do update the history
+              ;; because that is what the user's previous node choice into it.
+              (Info-history nil)
+              found)
+          (while
+              (progn
+                (goto-char (point-min))
+                (while (re-search-forward pattern nil t)
+                  (let ((entry (match-string-no-properties 1))
+                        (nodename (match-string-no-properties 3))
+                        (line (string-to-number (concat "0" (match-string 4)))))
+                    (add-text-properties
+                     (- (match-beginning 2) (match-beginning 1))
+                     (- (match-end 2) (match-beginning 1))
+                     '(face info-index-match) entry)
+                    (push (list entry nodename Info-current-node line) matches)))
+                (setq nodes (cdr nodes) node (car nodes)))
+            (Info-goto-node node))
+          (or matches
+              (progn
+                (Info-goto-node orignode)
+                (user-error "No `%s' in index" topic)))
+          ;; Here it is a feature that assoc is case-sensitive.
+          (while (setq found (assoc topic matches))
+            (setq exact (cons found exact)
+                  matches (delq found matches)))
           (setq Info-history-list ohist-list)
-	  (setq Info-index-alternatives (nconc exact (nreverse matches))
+          (setq Info-index-alternatives (nconc exact (nreverse matches))
                 Info--current-index-alternative 0)
-	  (Info-index-next 0)))))
+          (Info-index-next 0))))
+  (when Info-jump (select-window Info-jump)))
 
 (defun Info-index-next (num)
   "Go to the next matching index item from the last \\<Info-mode-map>\\[Info-index] command.
@@ -3411,45 +3530,49 @@ Info-index-next
 
 Also see the `Info-warn-on-index-alternatives-wrap' user option."
   (interactive "p" Info-mode)
-  (unless Info-index-alternatives
-    (user-error "No previous `i' command"))
-  (let ((index (+ Info--current-index-alternative num))
-        (total (length Info-index-alternatives))
-        (next-key (key-description (where-is-internal
-				    'Info-index-next overriding-local-map t))))
-    (if (and Info-warn-on-index-alternatives-wrap
-             (> total 1)
-             (cond
-              ((< index 0)
-               (setq Info--current-index-alternative (- total 2))
-               (message
-                "No previous matches, use `%s' to continue from end of list"
-                next-key)
-               t)
-              ((>= index total)
-               (setq Info--current-index-alternative -1)
-               (message
-                "No previous matches, use `%s' to continue from start of list"
-                next-key)
-               t)))
-        ()                              ; Do nothing
-      (setq index (mod index total)
-            Info--current-index-alternative index)
-      (let ((entry (nth index Info-index-alternatives)))
-        (Info-goto-node (nth 1 entry))
-        (if (> (nth 3 entry) 0)
-            ;; Forward 2 lines less because `Info-find-node-2' initially
-            ;; puts point to the 2nd line.
-            (forward-line (- (nth 3 entry) 2))
-          (forward-line 3)              ; don't search in headers
-          (Info-find-index-name (car entry)))
-        (message "Found `%s' in %s.  %s"
-	         (car entry)
-	         (nth 2 entry)
-	         (if (> total 1)
-	             (format-message
-                      "(%s total; use `%s' for next)" total next-key)
-	           "(Only match)"))))))
+  (let ((info-window (get-buffer-window "*info*")))
+    (unless (window-live-p info-window)
+      (user-error "There is no visible Info buffer."))
+    (with-selected-window info-window
+      (unless Info-index-alternatives
+        (user-error "No previous `i' command"))
+      (let ((index (+ Info--current-index-alternative num))
+            (total (length Info-index-alternatives))
+            (next-key (key-description (where-is-internal
+                                        'Info-index-next overriding-local-map t))))
+        (if (and Info-warn-on-index-alternatives-wrap
+                 (> total 1)
+                 (cond
+                  ((< index 0)
+                   (setq Info--current-index-alternative (- total 2))
+                   (message
+                    "No previous matches, use `%s' to continue from end of list"
+                    next-key)
+                   t)
+                  ((>= index total)
+                   (setq Info--current-index-alternative -1)
+                   (message
+                    "No previous matches, use `%s' to continue from start of list"
+                    next-key)
+                   t)))
+            ()                              ; Do nothing
+          (setq index (mod index total)
+                Info--current-index-alternative index)
+          (let ((entry (nth index Info-index-alternatives)))
+            (Info-goto-node (nth 1 entry))
+            (if (> (nth 3 entry) 0)
+                ;; Forward 2 lines less because `Info-find-node-2' initially
+                ;; puts point to the 2nd line.
+                (forward-line (- (nth 3 entry) 2))
+              (forward-line 3)              ; don't search in headers
+              (Info-find-index-name (car entry)))
+            (message "Found `%s' in %s.  %s"
+                     (car entry)
+                     (nth 2 entry)
+                     (if (> total 1)
+                         (format-message
+                          "(%s total; use `%s' for next)" total next-key)
+                       "(Only match)"))))))))
 
 (defun Info-find-index-name (name)
   "Move point to the place within the current node where NAME is defined."
@@ -3534,32 +3657,39 @@ Info-virtual-index
   ;; `interactive' is a copy from `Info-index'
   (interactive
    (list
-    (let ((completion-ignore-case t)
-	  (Info-complete-menu-buffer (clone-buffer))
-	  (Info-complete-nodes (Info-index-nodes))
-	  (Info-history-list nil))
-      (info--ensure-not-in-directory-node)
-      (unwind-protect
-	  (with-current-buffer Info-complete-menu-buffer
-	    (Info-goto-index)
-	    (completing-read "Index topic: " #'Info-complete-menu-item))
-	(kill-buffer Info-complete-menu-buffer))))
+    (let ((info-window (get-buffer-window "*info*")))
+      (unless (window-live-p info-window)
+        (user-error "There is no visible Info buffer."))
+      (if (not (eq (selected-window) info-window))
+          (Info-jump)
+        (setq Info-jump nil))
+      (let ((completion-ignore-case t)
+            (Info-complete-menu-buffer (clone-buffer))
+            (Info-complete-nodes (Info-index-nodes))
+            (Info-history-list nil))
+        (info--ensure-not-in-directory-node)
+        (unwind-protect
+            (with-current-buffer Info-complete-menu-buffer
+              (Info-goto-index)
+              (completing-read "Index topic: " #'Info-complete-menu-item))
+          (kill-buffer Info-complete-menu-buffer)))))
    Info-mode)
   (if (equal topic "")
       (Info-find-node Info-current-file "*Index*")
     (unless (assoc (cons Info-current-file topic) Info-virtual-index-nodes)
       (let ((orignode Info-current-node)
-	    (ohist-list Info-history-list))
-	;; Reuse `Info-index' to set `Info-index-alternatives'.
-	(Info-index topic)
-	(push (cons (cons Info-current-file topic) Info-index-alternatives)
-	      Info-virtual-index-nodes)
-	;; Clean up unnecessary side-effects of `Info-index'.
-	(setq Info-history-list ohist-list)
-	(Info-goto-node orignode)
-	(message "")))
+            (ohist-list Info-history-list))
+        ;; Reuse `Info-index' to set `Info-index-alternatives'.
+        (Info-index topic)
+        (push (cons (cons Info-current-file topic) Info-index-alternatives)
+              Info-virtual-index-nodes)
+        ;; Clean up unnecessary side-effects of `Info-index'.
+        (setq Info-history-list ohist-list)
+        (Info-goto-node orignode)
+        (message "")))
     (Info-find-node Info-current-file
-                    (format "*Index for ‘%s’*" topic))))
+                    (format "*Index for ‘%s’*" topic)))
+  (when Info-jump (Info-jump)))
 \f
 (add-to-list 'Info-virtual-files
 	     '("\\`\\*Apropos\\*\\'"
@@ -3696,18 +3826,22 @@ info-apropos
 
 Display a menu of the possible matches."
   (interactive "sIndex apropos: \nP")
-  (if (equal string "")
-      (Info-find-node Info-apropos-file "Top")
-    (let ((nodes Info-apropos-nodes)
-          nodename)
-      (while (and nodes (not (equal string (nth 1 (car nodes)))))
-	(setq nodes (cdr nodes)))
-      (if nodes
-	  (Info-find-node Info-apropos-file (car (car nodes)) nil nil t)
-	(setq nodename (format "Index for ‘%s’" string))
-	(push (list nodename string (Info-apropos-matches string regexp))
-	      Info-apropos-nodes)
-	(Info-find-node Info-apropos-file nodename)))))
+  (let ((info-window (get-buffer-window "*info*")))
+    (unless (window-live-p info-window)
+      (user-error "There is no visible Info buffer."))
+    (with-selected-window info-window
+      (if (equal string "")
+          (Info-find-node Info-apropos-file "Top")
+        (let ((nodes Info-apropos-nodes)
+              nodename)
+          (while (and nodes (not (equal string (nth 1 (car nodes)))))
+            (setq nodes (cdr nodes)))
+          (if nodes
+              (Info-find-node Info-apropos-file (car (car nodes)) nil nil t)
+            (setq nodename (format "Index for ‘%s’" string))
+            (push (list nodename string (Info-apropos-matches string regexp))
+                  Info-apropos-nodes)
+            (Info-find-node Info-apropos-file nodename)))))))
 \f
 (add-to-list 'Info-virtual-files
 	     '("\\`\\*Finder.*\\*\\'"
@@ -3842,17 +3976,29 @@ info-finder
   (interactive
    (when current-prefix-arg
      (require 'finder)
-     (list
-      (completing-read-multiple
-       "Keywords (separated by comma): "
-       (mapcar #'symbol-name (mapcar #'car (append finder-known-keywords
-                                                   (finder-unknown-keywords))))
-       nil t))))
+     (let ((info-window (get-buffer-window "*info*")))
+       (unless (window-live-p info-window)
+         (user-error "There is no visible Info buffer."))
+       (if (not (eq (selected-window) info-window))
+           (Info-jump)
+         (setq Info-jump nil))
+       (list
+        (completing-read-multiple
+         "Keywords (separated by comma): "
+         (mapcar #'symbol-name (mapcar #'car (append finder-known-keywords
+                                                     (finder-unknown-keywords))))
+         nil t)))))
   (require 'finder)
-  (if keywords
-      (Info-find-node Info-finder-file (mapconcat 'identity keywords ", "))
-    (Info-find-node Info-finder-file "Top")))
-
+  (let ((info-window (get-buffer-window "*info*")))
+    (unless (window-live-p info-window)
+      (user-error "There is no visible Info buffer."))
+    (if (not (eq (selected-window) info-window))
+        (Info-jump)
+      (setq Info-jump nil))
+    (if keywords
+        (Info-find-node Info-finder-file (mapconcat 'identity keywords ", "))
+      (Info-find-node Info-finder-file "Top")))
+  (when Info-jump (Info-jump)))
 \f
 (defun Info-undefined ()
   "Make command be undefined in Info."
@@ -3871,22 +4017,26 @@ Info-help
 (defun Info-summary ()
   "Display a brief summary of all Info commands."
   (interactive)
-  (save-window-excursion
-    (switch-to-buffer "*Help*")
-    (setq buffer-read-only nil)
-    (erase-buffer)
-    (insert (documentation 'Info-mode))
-    (help-mode)
-    (goto-char (point-min))
-    (let (ch flag)
-      (while (progn (setq flag (not (pos-visible-in-window-p (point-max))))
-		    (message (if flag "Type Space to see more"
-			       "Type Space to return to Info"))
-		    (if (not (eq ?\s (setq ch (read-event))))
-			(progn (push ch unread-command-events) nil)
-		      flag))
-	(scroll-up)))
-    (bury-buffer "*Help*")))
+  (let ((info-window (get-buffer-window "*info*")))
+    (unless (window-live-p info-window)
+      (user-error "There is no visible Info buffer."))
+    (with-selected-window info-window
+      (save-window-excursion
+        (switch-to-buffer "*Help*")
+        (setq buffer-read-only nil)
+        (erase-buffer)
+        (insert (documentation 'Info-mode))
+        (help-mode)
+        (goto-char (point-min))
+        (let (ch flag)
+          (while (progn (setq flag (not (pos-visible-in-window-p (point-max))))
+                        (message (if flag "Type Space to see more"
+                                   "Type Space to return to Info"))
+                        (if (not (eq ?\s (setq ch (read-event))))
+                            (progn (push ch unread-command-events) nil)
+                          flag))
+            (scroll-up)))
+        (bury-buffer "*Help*")))))
 \f
 (defun Info-get-token (pos start all &optional errorstring)
   "Return the token around POS.
@@ -4038,7 +4188,7 @@ Info-mouse-follow-link
 (defvar Info-mode-map
   (let ((map (make-keymap)))
     (suppress-keymap map)
-    (define-key map "." 'beginning-of-buffer)
+    (define-key map "." 'Info-beginning-of-buffer)
     (define-key map " " 'Info-scroll-up)
     (define-key map [?\S-\ ] 'Info-scroll-down)
     (define-key map "\C-m" 'Info-follow-nearest-node)
@@ -4060,10 +4210,10 @@ Info-mode-map
     (define-key map "[" 'Info-backward-node)
     (define-key map "<" 'Info-top-node)
     (define-key map ">" 'Info-final-node)
-    (define-key map "b" 'beginning-of-buffer)
+    (define-key map "b" 'Info-beginning-of-buffer)
     (put 'beginning-of-buffer :advertised-binding "b")
     (define-key map "d" 'Info-directory)
-    (define-key map "e" 'end-of-buffer)
+    (define-key map "e" 'Info-end-of-buffer)
     (define-key map "f" 'Info-follow-reference)
     (define-key map "g" 'Info-goto-node)
     (define-key map "G" 'Info-goto-node-web)
@@ -4071,15 +4221,16 @@ Info-mode-map
     ;; This is for compatibility with standalone info (>~ version 5.2).
     ;; Though for some time, standalone info had H and h reversed.
     ;; See <https://debbugs.gnu.org/16455>.
-    (define-key map "H" 'describe-mode)
+    (define-key map "H" 'Info-describe-mode)
     (define-key map "i" 'Info-index)
+    (define-key map "j" 'Info-jump)
     (define-key map "I" 'Info-virtual-index)
     (define-key map "l" 'Info-history-back)
     (define-key map "L" 'Info-history)
     (define-key map "m" 'Info-menu)
     (define-key map "n" 'Info-next)
     (define-key map "p" 'Info-prev)
-    (define-key map "q" 'quit-window)
+    (define-key map "q" 'Info-quit-window)
     (define-key map "r" 'Info-history-forward)
     (define-key map "s" 'Info-search)
     (define-key map "S" 'Info-search-case-sensitively)
@@ -4104,6 +4255,21 @@ Info-mode-map
     map)
   "Keymap containing Info commands.")
 
+;; with a little help from Helm
+(defcustom Info-mode-prefix-key "C-h M-i"
+  "`Info-mode-map' prefix key for invocation from other buffers."
+  :version "30.1"
+  :type '(choice (string :tag "Key") (const :tag "no binding"))
+  :set (lambda (var key)
+         (when (and (boundp var) (symbol-value var))
+           (define-key (current-global-map)
+                       (read-kbd-macro (symbol-value var)) nil))
+         (when key
+           (define-key (current-global-map)
+                       (read-kbd-macro key)
+                       Info-mode-map))
+         (set var key))
+  :group 'info)
 
 (defun Info-check-pointer (item)
   "Non-nil if ITEM is present in this node."
@@ -4125,7 +4291,7 @@ Info-check-pointer
     :help "Go backward one node, considering all as a sequence"]
    ["Forward" Info-forward-node
     :help "Go forward one node, considering all as a sequence"]
-   ["Beginning" beginning-of-buffer
+   ["Beginning" Info-beginning-of-buffer
     :help "Go to beginning of this node"]
    ["Top" Info-top-node
     :help "Go to top node of file"]
@@ -4323,20 +4489,24 @@ Info-copy-current-node-name
 The name of the Info file is prepended to the node name in parentheses.
 With a zero prefix arg, put the name inside a function call to `info'."
   (interactive "P" Info-mode)
-  (unless Info-current-node
-    (user-error "No current Info node"))
-  (let ((node (if (stringp Info-current-file)
-		  (concat "(" (file-name-sans-extension
-			       (file-name-nondirectory Info-current-file))
-			  ") "
-			  Info-current-node))))
-    (if (zerop (prefix-numeric-value arg))
-        (setq node (concat "(info \"" node "\")")))
-    (unless (stringp Info-current-file)
-      (setq node (format "(Info-find-node '%S '%S)"
-			 Info-current-file Info-current-node)))
-    (kill-new node)
-    (message "%s" node)))
+  (let ((info-window (get-buffer-window "*info*")))
+    (unless (window-live-p info-window)
+      (user-error "There is no visible Info buffer."))
+    (with-selected-window info-window
+      (unless Info-current-node
+        (user-error "No current Info node"))
+      (let ((node (if (stringp Info-current-file)
+		      (concat "(" (file-name-sans-extension
+			           (file-name-nondirectory Info-current-file))
+			      ") "
+			      Info-current-node))))
+        (if (zerop (prefix-numeric-value arg))
+            (setq node (concat "(info \"" node "\")")))
+        (unless (stringp Info-current-file)
+          (setq node (format "(Info-find-node '%S '%S)"
+			     Info-current-file Info-current-node)))
+        (kill-new node)
+        (message "%s" node)))))
 
 \f
 ;; Info mode is suitable only for specially formatted data.
@@ -5509,6 +5679,42 @@ info--manual-names
 			    (apply-partially #'Info-read-node-name-2
 					     Info-directory-list
 					     (mapcar #'car Info-suffix-list))))))))
+\f
+;; commands from special-mode wrapped to work on Info-mode only
+
+(defun Info-beginning-of-buffer ()
+  "Move point to the beginning of *info* buffer."
+  (interactive)
+  (let ((info-window (get-buffer-window "*info*")))
+    (unless (window-live-p info-window)
+      (user-error "There is no visible Info buffer."))
+    (with-selected-window info-window
+      (goto-char (point-min)))))
+
+(defun Info-end-of-buffer ()
+  "Move point to the beginning of *info* buffer."
+  (interactive)
+  (let ((info-window (get-buffer-window "*info*")))
+    (unless (window-live-p info-window)
+      (user-error "There is no visible Info buffer."))
+    (with-selected-window info-window
+      (goto-char (point-max)))))
+
+(defun Info-describe-mode ()
+  "As `describe-mode' but for *Help* buffer only."
+  (interactive)
+  (let ((info-window (get-buffer "*info*")))
+    (unless (window-live-p (get-buffer-window info-window))
+      (user-error "There is no visible Info buffer."))
+    (describe-mode info-window)))
+
+(defun Info-quit-window ()
+  (interactive)
+  (let ((info-window (get-buffer-window "*info*")))
+    (unless (window-live-p info-window)
+      (user-error "There is no visible Info buffer."))
+    (with-selected-window info-window
+      (quit-window nil info-window))))
 
 (provide 'info)
 
-- 
2.40.1


^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2023-05-30 12:38 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-05-30 12:38 Proposal: Control help- and Info-mode buffers from other buffers Arthur Miller

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).