¿Cómo controlar dónde se muestra el búfer de palabras clave org todo?

9

P : ¿cómo puedo controlar dónde orgaparece el búfer de palabras clave de todo?

Al ingresar una todopalabra clave con C-c C-t( org-todo), se abre un nuevo búfer con las opciones de palabras clave y luego se cierra nuevamente después de seleccionar una. Hasta aquí todo bien. Sin embargo, se necesita otra ventana para hacerlo, lo cual es menos bueno, especialmente porque realmente solo necesita mostrar una o dos líneas con las palabras clave.

Entonces, con el siguiente diseño, presionar C-c C-tmientras está en la ventana izquierda ( some-org-buffer) se abrirá *Org todo*en la ventana derecha:

+---------------------+---------------------+
|                     |                     |
|                     |                     |
|                     |                     |
|                     |                     |
|   some-org-buffer   |  some-other-buffer  |
|                     |                     |
|                     |                     |
|                     |                     |
|                     |                     |
+---------------------+---------------------+

En cambio, me gustaría tener una pequeña ventana emergente como una división vertical, como se muestra a continuación:

+---------------------+---------------------+
|                     |                     |
|                     |                     |
|   some-org-buffer   |  some-other-buffer  |
|                     |                     |
|                     |                     |
+---------------------+                     |
|                     |                     |
|     *Org todo*      |                     |
|                     |                     |
+---------------------+---------------------+

A pesar de esta respuesta , escribí una función para poner en display-buffer-alist:

(defun org-todo-position (buffer alist)
  (let ((win (car (cl-delete-if-not
                   (lambda (window)
                     (with-current-buffer (window-buffer window)
                       (memq major-mode
                             '(org-mode org-agenda-mode))))
                   (window-list)))))
    (when win
      (let ((new (split-window win -5 'below)))
        (set-window-buffer new buffer)
        new))))

(add-to-list 'display-buffer-alist
             (list " \\*Org todo\\*" #'dan-org-todo-position))

Sin embargo, eso no funciona. Suspiro. ¿Qué he hecho mal con el display-buffer-alist? Más concretamente, ¿cómo hago para que mi todobúfer de palabras clave aparezca donde lo quiero?

Dan
fuente
No es una respuesta a su pregunta, pero es posible que desee considerar modificar org-switch-to-buffer-other-windowpara hacer lo que quiera: puede crear una condición que haga lo que quiera.
ley
@lawlist: gracias, busqué y descubrí org-switch-to-buffer-other-windowun montón de otras orgentrañas feas . Vea la respuesta para la ignominiosa "solución".
Dan
Al incorporar todo esto en mis .emacs, examiné de cerca tu función de posicionamiento y siento que me falta algo con respecto a tu definición de win. ¿Hay alguna razón que no puedas usar (selected-window)aquí?
Aaron Harris
@AaronHarris: no lo he probado; Había adaptado (ligeramente) una respuesta de una publicación diferente que usaba este mecanismo. Darle una oportunidad y ver si funciona.
Dan
@Dan: Sí, funciona. Estaba un poco preocupado de que alguna situación de esquina podría hacer que explotara. Y gracias por esa función, por cierto. Hace exactamente lo que quiero que haga, y no creo que hubiera podido articular que eso era lo que quería antes de ver esta pregunta.
Aaron Harris

Respuestas:

4

Suspiro. Encontré una "solución", pero es fea y requiere sobrescribir una orgfunción existente . Preferiría uno que no requiera modificar el orgcódigo fuente, pero estoy poniendo los resultados de mi excavación arqueológica aquí en caso de que alguien más pueda usarlo.

Como he notado en el pasado con otras orgfunciones, org-modees bastante obstinado sobre cómo maneja las ventanas.

Enterrado en lo profundo del código fuente de org-todoes una llamada a la función org-fast-todo-selection. Esa función, a su vez, llama org-switch-to-buffer-other-window, cuya cadena de documentos se lee, en parte:

Cambie al búfer en una segunda ventana en el marco actual. En particular, no permita marcos emergentes .

UH oh.

Bien, voy a morder: echemos un vistazo org-switch-to-buffer-other-window. Utiliza la org-no-popups macro. Su cadena de documentos lee, en parte:

Suprimir ventanas emergentes. Vinculamos algunas variables a cero alrededor de BODY ...

Resulta que esa display-buffer-alistes una de las variables let-bound to nil.

( Cabeza explota )

En última instancia, podemos lograr que no se ignore display-buffer-alisteditando org-fast-todo-selectiony reemplazando la org-switch-to-buffer-other-windowlínea por la antigua switch-to-buffer-other-window:

(defun org-fast-todo-selection ()
  "Fast TODO keyword selection with single keys.
Returns the new TODO keyword, or nil if no state change should occur."
  (let* ((fulltable org-todo-key-alist)
     (done-keywords org-done-keywords) ;; needed for the faces.
     (maxlen (apply 'max (mapcar
                  (lambda (x)
                (if (stringp (car x)) (string-width (car x)) 0))
                  fulltable)))
     (expert nil)
     (fwidth (+ maxlen 3 1 3))
     (ncol (/ (- (window-width) 4) fwidth))
     tg cnt e c tbl
     groups ingroup)
    (save-excursion
      (save-window-excursion
    (if expert
        (set-buffer (get-buffer-create " *Org todo*"))
      ;; (org-switch-to-buffer-other-window (get-buffer-create " *Org todo*")))
      (switch-to-buffer-other-window (get-buffer-create " *Org todo*")))
    (erase-buffer)
    (org-set-local 'org-done-keywords done-keywords)
    (setq tbl fulltable cnt 0)
    (while (setq e (pop tbl))
      (cond
       ((equal e '(:startgroup))
        (push '() groups) (setq ingroup t)
        (when (not (= cnt 0))
          (setq cnt 0)
          (insert "\n"))
        (insert "{ "))
       ((equal e '(:endgroup))
        (setq ingroup nil cnt 0)
        (insert "}\n"))
       ((equal e '(:newline))
        (when (not (= cnt 0))
          (setq cnt 0)
          (insert "\n")
          (setq e (car tbl))
          (while (equal (car tbl) '(:newline))
        (insert "\n")
        (setq tbl (cdr tbl)))))
       (t
        (setq tg (car e) c (cdr e))
        (if ingroup (push tg (car groups)))
        (setq tg (org-add-props tg nil 'face
                    (org-get-todo-face tg)))
        (if (and (= cnt 0) (not ingroup)) (insert "  "))
        (insert "[" c "] " tg (make-string
                   (- fwidth 4 (length tg)) ?\ ))
        (when (= (setq cnt (1+ cnt)) ncol)
          (insert "\n")
          (if ingroup (insert "  "))
          (setq cnt 0)))))
    (insert "\n")
    (goto-char (point-min))
    (if (not expert) (org-fit-window-to-buffer))
    (message "[a-z..]:Set [SPC]:clear")
    (setq c (let ((inhibit-quit t)) (read-char-exclusive)))
    (cond
     ((or (= c ?\C-g)
          (and (= c ?q) (not (rassoc c fulltable))))
      (setq quit-flag t))
     ((= c ?\ ) nil)
     ((setq e (rassoc c fulltable) tg (car e))
      tg)
     (t (setq quit-flag t)))))))
Dan
fuente
¿Podrías usar cl fletaquí para volver a vincular org-switch-to-buffer-other-window? Preguntándome si puede aconsejar o envolver en org-fast-todo-selectionlugar de sobrescribirlo.
glucas
@glucas: buena idea. Sin embargo, lo probé y no pude hacerlo funcionar.
Dan
1
@Dan, pude hacer que esto funcione redefiniendo org-switch-to-buffer-other-windowa solo (switch-to-buffer-other-window args). También eliminé &restlos argumentos de la función.
sk8ingdom
3

Recientemente descubrí cómo hacer la captura en modo Org en un nuevo marco . Modificar ese código para usar su función es bastante sencillo. Así es como lo haría:

(defun my/org-todo-window-advice (orig-fn)
  "Advice to fix window placement in `org-fast-todo-selection'."
  (let  ((override '("\\*Org todo\\*" dan-org-todo-position)))
    (add-to-list 'display-buffer-alist override)
    (my/with-advice
        ((#'org-switch-to-buffer-other-window :override #'pop-to-buffer))
      (unwind-protect (funcall orig-fn)
        (setq display-buffer-alist
              (delete override display-buffer-alist))))))

(advice-add #'org-fast-todo-selection :around #'my/org-todo-window-advice)

Para completar, aquí está la definición de la my/with-advicemacro de la otra respuesta:

(defmacro my/with-advice (adlist &rest body)
  "Execute BODY with temporary advice in ADLIST.

Each element of ADLIST should be a list of the form
  (SYMBOL WHERE FUNCTION [PROPS])
suitable for passing to `advice-add'.  The BODY is wrapped in an
`unwind-protect' form, so the advice will be removed even in the
event of an error or nonlocal exit."
  (declare (debug ((&rest (&rest form)) body))
           (indent 1))
  `(progn
     ,@(mapcar (lambda (adform)
                 (cons 'advice-add adform))
               adlist)
     (unwind-protect (progn ,@body)
       ,@(mapcar (lambda (adform)
                   `(advice-remove ,(car adform) ,(nth 2 adform)))
                 adlist))))
Aaron Harris
fuente
2

Buscando en algún otro config , he encontrado una manera de control donde *Org Src.*y *Org todo*aparecen tampones. Ahora, cuando presiono C-c C-to C-c 'estos buffers se muestran en una nueva ventana en la parte inferior de mi diseño de ventana actual, y al seleccionar un estado TODO o presionar C-c '( org-edit-src-exit), la configuración de mi ventana vuelve a su diseño original.

Esta solución implica el uso de grilletes y algo de Elisp:

Paso 1

Descargar shackledesde MELPA. Así es como lo configuré use-packageen mi archivo init:

(use-package shackle
    :ensure t
    :diminish shackle-mode  ; hide name in mode-line
    :config
    (setq shackle-rules
          '(("\\*Org Src.*" :regexp t :align below :select t)
            (" *Org todo*" :align below :select t)))
    (shackle-mode t))

Las configuraciones importantes aquí son:

(setq shackle-rules
              '(("\\*Org Src.*" :regexp t :align below :select t)
                (" *Org todo*" :align below :select t)))

Fuente

Tenga en cuenta especialmente el espacio entre "y *Orgen la línea inferior. No he probado la configuración :alignen otras ubicaciones, pero shackleparece ser bastante flexible, por lo que vale la pena leer la documentación y experimentar con ella.

Paso 2

Ahora hacemos org-modeescuchar shacklecon un poco más de Elisp en nuestro archivo init. Para obtener *Org Src.*buffers a seguir shackle-rules:

(setq org-src-window-setup 'other-window)

Fuente

Lamentablemente org-mode, no proporciona una configuración análoga para las *Org todo*memorias intermedias. Este truco lo compensa (y probablemente sea (setq org-src-window-setup 'other-window)superfluo, pero alguien más conocedor tendrá que intervenir):

;; Re-define org-switch-to-buffer-other-window to NOT use org-no-popups.
;; Primarily for compatibility with shackle.
(defun org-switch-to-buffer-other-window (args)
  "Switch to buffer in a second window on the current frame.
In particular, do not allow pop-up frames.
Returns the newly created buffer.
Redefined to allow pop-up windows."
  ;;  (org-no-popups
  ;;     (apply 'switch-to-buffer-other-window args)))
  (switch-to-buffer-other-window args))

Fuente

tirocinio
fuente