Cómo mostrar un búfer de ayuda / tamaño de cuadro completo de ventana (no pantalla completa)

8

A veces quiero mostrar información en el estilo del búfer de ayuda, por lo que he estado usando un código como este:

(with-help-window (help-buffer)
  (princ "Type q to exit this help buffer.\n\n")
  (princ result))

Esto funciona bien, pero la ventana de ayuda solo usa la mitad de mi marco. Normalmente divido mi marco horizontalmente, para dar dos ventanas altas. El búfer de ayuda que se muestra utiliza una de las dos ventanas.

Preferiría usar todo el marco en algunos casos, para mostrar más información y reducir la cantidad de veces que necesito desplazarme por la información mostrada. El problema a resolver es cómo usar temporalmente el marco completo para la with-help-windowllamada y restaurar automáticamente los tampones / tamaños de ventana originales cuando escribo "q" en la ventana de ayuda.

¿Cómo puedo lograr mejor este objetivo? Creo que estoy buscando algo como esto:

(with-FULL-FRAME-help-window (help-buffer)
   ...)

He examinado el modo ganador, marcadores, guardar diseños en registros, los diversos (y potentes, pero complejos) (display-buffer ...)métodos. La mayoría de ellos parecen ligeramente desviados de mi intención deseada porque tienden a corregir / restaurar un diseño después de una operación de visualización de fotograma completo. Y me parece que muchos de ellos requieren que restaure manualmente el diseño de mi ventana (lo que preferiría no hacer).

Me pregunto si alguien ha oído hablar de una manera de resolver esto simplemente. Espero algo simple como estos posibles enfoques, donde puedo anular algo con un marco let ...

(let ((help-window-width-display-option fullwidth))
  (with-help-window (help-buffer)
    ...))

O este tipo de enfoque, que aún no sé cómo hacer, y que parece un tanto difícil / complicado para mi nivel de habilidad actual.

(let ((save original configuration somehow)
  (delete-other-windows)
  (with-help-window (help-buffer)
     ...)
  ;; somehow, when I type "q" in the help buffer
  ;; - catch that action in code after the buffer is killed
  ;; - and restore the original window configuration
  )

Me parece que el problema clave que debo resolver es cómo restaurar automáticamente la configuración original de la ventana cuando escribo "q" en el búfer temporal del modo de ayuda. Gracias

Kevin
fuente
Una idea sería usar display-buffer-pop-up-frame: gnu.org/software/emacs/manual/html_node/elisp/… Otra idea sería emitir un make-frame tiempo usando display-bufferuna función personalizada para apuntar a ese nuevo marco. Si está interesado en localizar y orientar un marco existente, eche un vistazo a este ejemplo: stackoverflow.com/questions/18346785/…
lawlist
Aquí hay una idea de cómo guardar y restaurar la configuración de su ventana para que pueda usar el marco existente: emacs.stackexchange.com/a/2714/2287 Si considera que, al igual que ciertas configuraciones de ventana, puede considerar establecer algo eso es más elaborado: hay varias bibliotecas que se ocupan de guardar y cambiar entre varias configuraciones de ventana.
abogados
Como es habitual en la lista de leyes, gracias por su ayuda. Ya lo he intentado display-buffer-pop-up-frame, ya que está bastante cerca de lo que busco. Pero ... el marco aparece en otro lugar (no mi marco actual), y debo enviarlo con cmd-w, no "q" en estilo de ayuda. Guardar / restaurar configuraciones de ventana no es el problema subyacente. Actualmente me estoy inclinando hacia la clonación y la modificación de la fuente de la ventana con ayuda para darle una opción que pueda vincular o envolver con un defmacro o algo así. Sonrío por lo exigentes que somos las personas de emacs que queremos exactamente lo que queremos de Emacs.
Kevin
Después de leer más en help.el, la solución parece ser enterrado en algún lugar help-return-method, quit-windowel quit-restoreparámetro de ventana, y probablemente algún código personalizado para set / usar todas esas cosas para crear el efecto deseado.
Kevin

Respuestas:

5

Ejemplo # 1 : El atajo de teclado qen el help-modebúfer proviene del special-mode-mapque está incorporado en el help-mode-map. El valor predeterminado es quit-window, que ofrece solo cuatro (4) acciones posibles: " De acuerdo con la información almacenada en el quit-restoreparámetro de ventana de WINDOW, (1) elimine WINDOW y su marco, (2) elimine WINDOW, (3) restaure el búfer mostrado previamente en WINDOW , o (4) hacer que WINDOW muestre algún otro búfer que el actual. Si no es nulo, restablezca el quit-restoreparámetro a nil. "[Ver doc-string: M-x describe-function RET quit-window RET]

Aquí hay un resumen de lo que hace este ejemplo:

  • Vincular la variable help-window-selecta tpara que *Help*se seleccione la ventana.

  • Enlace la configuración de la ventana actual a una variable temporal llamada config.

  • Genera la *Help*ventana.

  • Almacene la configuración de ventana anterior config- en una variable local llamada my-stored-win-config.

  • Cree una asignación de clave local para la letra q, que está vinculada my-restore-win-config. [Esta asignación local triunfa / sombrea la asignación anterior de quit-window.]

  • Eliminar otras ventanas.

  • Presione la letra qpara restaurar la configuración de la ventana anterior y elimine el *Help*búfer.

(defvar my-stored-win-config nil)
(make-variable-buffer-local 'my-stored-win-config)

(defun my-restore-win-config ()
  (interactive)
  (when my-stored-win-config
    (set-window-configuration my-stored-win-config)
    (kill-buffer "*Help*")))

El siguiente fragmento es un uso de muestra, pero no es una función interactiva completa. Se puede evaluar en el *scratch*búfer para verlo en acción.

(let ((help-window-select t)
      (config (current-window-configuration)))
  (with-help-window (help-buffer)
    (princ "Type q to kill this *Help* buffer and restore prior window configuration."))
  (with-current-buffer "*Help*"
    (setq my-stored-win-config config)
    (local-set-key "q" 'my-restore-win-config))
  (delete-other-windows))

Ejemplo # 2 :

Aquí hay una macro autónoma que hace todo como el ejemplo anterior, que trata con tres situaciones posibles relacionadas con los valores de enlace existentes, por ejemplo nil, símbolo o lista de símbolos.

(defmacro help-window-full-frame (buffer-name &rest body)
"Doc-string."
  (declare (indent 1) (debug t))
  `(progn
    (set-marker help-window-point-marker nil)
      (let* (
          (help-window-select t)
          (foo
            (lambda ()
              (set (make-local-variable 'window-configuration)
                (current-window-configuration))
              (local-set-key "q"
                (lambda ()
                  (interactive)
                  (when window-configuration
                    ;; Record the `current-buffer' before it gets buried.
                    (let ((cb (current-buffer)))
                      (set-window-configuration window-configuration)
                      (kill-buffer cb)))))))
          ;; Preserve the original hook values by let-binding them in advance.
          ;; Otherwise, `add-to-list' would alter the global value.
          (temp-buffer-window-setup-hook temp-buffer-window-setup-hook)
          (temp-buffer-window-show-hook temp-buffer-window-show-hook)
          (temp-buffer-window-setup-hook
            (cond
              ((null temp-buffer-window-setup-hook)
                (list 'help-mode-setup foo))
              ((and
                  (not (null temp-buffer-window-setup-hook))
                  (listp temp-buffer-window-setup-hook))
                (add-to-list 'temp-buffer-window-setup-hook foo)
                (add-to-list 'temp-buffer-window-setup-hook 'help-mode-setup))
              ((and
                  (not (null temp-buffer-window-setup-hook))
                  (symbolp temp-buffer-window-setup-hook))
                (list 'help-mode-setup foo temp-buffer-window-setup-hook))))
          (temp-buffer-window-show-hook
            (cond
              ((null temp-buffer-window-show-hook)
                (list 'help-mode-finish 'delete-other-windows))
              ((and
                  (not (null temp-buffer-window-show-hook))
                  (listp temp-buffer-window-show-hook))
                (add-to-list 'temp-buffer-window-show-hook 'delete-other-windows)
                (add-to-list 'temp-buffer-window-show-hook 'help-mode-finish))
              ((and
                  (not (null temp-buffer-window-show-hook))
                  (symbolp temp-buffer-window-show-hook))
                (list
                  'help-mode-finish
                  'delete-other-windows
                  temp-buffer-window-show-hook)))) )
        (with-temp-buffer-window ,buffer-name nil 'help-window-setup (progn ,@body)))))

Y aquí está el fragmento de muestra para evaluar en el *scratch*búfer.

(help-window-full-frame (help-buffer)
  (princ "Type q to kill this *Help* buffer and restore prior window configuration."))
lista de leyes
fuente
Wow, gracias por una excelente respuesta. Había progresado para guardar / restaurar la configuración de la ventana, y había creado una my-help-quitfunción, al intentar volver a vincular la clave del mapa de ayuda dentro de with-help-window. Pero no estaba funcionando. Ahora veo que vincula la clave dentro del búfer de Ayuda (no en la ventana de Ayuda como estaba haciendo) después de configurar el búfer. Supongo que mi enlace fue golpeado por la configuración del búfer. Una lección aprendida. Todo está funcionando ahora. Muchas gracias.
Kevin
Hay dos (2) oportunidades para actuar directamente sobre el *Help*búfer antes de que finalice: el temp-buffer-window-setup-hookque se ejecuta help-mode-setupy luego cualquier otra cosa ya asignada previamente al gancho; y, luego, el temp-buffer-window-show-hookque se ejecuta help-mode-finishy todo lo que ya se haya asignado previamente al gancho. help-mode-setupdebe permanecer primero en el tiempo, pero puede agregar algo detrás uniendo cualquiera de esos ganchos antes mencionados con cosas personalizadas. En ese escenario, no lo necesitarías with-current-buffer.
abogados el
Convenido. Miré a ambos help-mode-setupy help-mode-finish, pero ambos corrieron antes de que se mostrara el búfer. El problema clave era redirigir la combinación de teclas "q", y usted me mostró cómo hacerlo en el búfer (no en la ventana, que estaba tratando de hacer). PD. Traté de escribir una solución como (defmacro with-full-frame-help-window, pero la macro todavía requiere una función separada para manejar la "q" y la acción de restauración de la ventana. Publicaré mis funciones completadas a continuación.
Kevin
Actualicé la respuesta con un segundo ejemplo que usa una macro autónoma que hace todo lo que hace el primer ejemplo.
abogados
1
Esto también funciona para mí, para reemplazar la referencia de búfer " Ayuda " codificada al búfer actual, porque la restauración lambda es una función local de búfer. ... (kill-buffer (current-buffer)))))). La macro tomó un nombre de búfer como argumento y eliminó " Ayuda ", por lo que podría haber un problema si la persona que llama utilizara un búfer cuyo nombre fuera diferente. Modifiqué mi macro para eliminar el buffer-nameparámetro y generé / eliminé el mismo búfer dentro del defmacro.
Kevin
3

Basado en la excelente respuesta de @lawlist, aquí están mis funciones completas para el próximo tipo ...

;; a tmp buffer-local place that gets destroyed with the help buffer
(defvar kwj-v-window-config-saved nil)
(make-variable-buffer-local 'kwj-v-window-config-saved)

(defun kwj-help-window-full-frame (string)
  "Show STRING in a help buffer using the full current frame."
  (let (original-layout)
    ;; set this before Help changes the config
    (setq original-layout (current-window-configuration))
    (with-help-window (help-buffer)
      (princ "Type q to exit this help buffer.\n\n")
      (princ string))
    (with-current-buffer "*Help*"
      ;; save layout in buffer local var that gets deleted
      (setq kwj-v-window-config-saved original-layout)
      ;; bind key in BUFFER (not in help window above)
      ;; bind key *after* help buf is displayed
      (local-set-key "q" 'kwj-help-window-restore))
    (delete-other-windows)))

(defun kwj-help-window-restore ()
  "Restore original windows after a full frame help display."
  (interactive)
  (set-window-configuration kwj-v-window-config-saved)
  (kill-buffer "*Help*"))

La larga cadena de comentarios anteriores, con la ayuda continua de @lawlist, dio como resultado esta versión de una macro que no requiere un nombre de búfer, trata adecuadamente las listas de enlace de configuración / show originales, y eso no causa problemas con el "q "en otros buffers del modo Ayuda .

(defmacro with-help-window-full-frame (&rest body)
  "Display text in a full-frame help window.
Execute BODY forms to put output into the window, with standard
output directed to the buffer."
  ;;tell indenter about this macro name
  (declare (indent 1))
  ;; must use a buffer string name here, not the buffer itself
  `(let ((mybuf ,(buffer-name (get-buffer-create "Full Frame Help")))
         ;;`(let ((mybuf ,(help-buffer))
         mysetup tmpsetup tmpshow)
     ;; save a copy of original hooks
     (setq tmpsetup (copy-list temp-buffer-window-setup-hook))
     (setq tmpshow (copy-list temp-buffer-window-show-hook))

     ;; create window config store and restore functions
     ;; credit to @lawlist on stackoverflow for this embedded setup
     (setq mysetup
           (lambda ()
             ;; store original window configuration
             (set (make-local-variable 'orig-win-config)
                  (current-window-configuration))
             ;; bind q to the window restore function
             (local-set-key
              "q"
              (lambda ()
                (interactive)
                ;; q is shared by all Help-mode buffers
                ;; so guard those that did not set up orig-win-config
                (when (boundp 'orig-win-config)
                  (set-window-configuration orig-win-config))
                (kill-buffer (current-buffer))))))

     ;; Add to help setup hooks. Keep original hook functions if any
     ;; delete-dups destructively hacks our tmp copy, not original hooklists
     (push mysetup tmpsetup)          ;order critical here
     (push 'help-mode-setup tmpsetup) ;this must be first in hook
     (delete-dups tmpsetup)

     (push 'help-mode-finish tmpshow) ;order not important here
     (push 'delete-other-windows tmpshow)
     (delete-dups tmpshow)

     ;; shadow the original hooks with our copies for the display call
     (let ((temp-buffer-window-setup-hook tmpsetup)
           (temp-buffer-window-show-hook tmpshow))

       ;; show buf with locally embedded window restore function
       (with-temp-buffer-window mybuf nil
                                'help-window-setup
                                (progn ,@body)))))

Use la macro de esta manera:

(with-help-window-full-frame
    (princ "Type q to exit this buffer."))
Kevin
fuente