Come controllare dove viene visualizzato il buffer delle parole chiave dell'organizzazione?


9

D : come posso controllare dove orgappare il buffer delle parole chiave todo?

L'immissione di una todoparola chiave con C-c C-t( org-todo) apre un nuovo buffer con le opzioni della parola chiave e la richiude dopo averne selezionato uno. Fin qui tutto bene. Tuttavia, ci vuole un'altra finestra per farlo, il che è meno buono, soprattutto perché ha solo bisogno di visualizzare una o due righe con le parole chiave.

Quindi, con il seguente layout, colpire C-c C-tmentre nella finestra di sinistra ( some-org-buffer) si aprirà *Org todo*nella finestra di destra:

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

Vorrei invece far apparire una piccola finestra come una divisione verticale, come di seguito:

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

Paralizzando da questa risposta , ho scritto una funzione per inserire 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))

Tuttavia, ciò non funziona. Sospiro. Cosa ho fatto di sbagliato in display-buffer-alist? Più precisamente, come posso visualizzare il todobuffer delle parole chiave nel punto desiderato?


Non è una risposta alla tua domanda, ma potresti prendere in considerazione la possibilità di modificare org-switch-to-buffer-other-windowper fare ciò che desideri: puoi creare una condizione che fa quello che vuoi.
— elenco delle leggi del

@lawlist: grazie, ho scavato e scoperto org-switch-to-buffer-other-windowe un sacco di altre brutte orginteriora. Vedi la risposta per la "soluzione" ignominiosa.
— Dan

Pur incorporando tutto questo nel mio .emacs, ho dato uno sguardo da vicino alla tua funzione di posizionamento e sento che mi manca qualcosa riguardo alla tua definizione di win. C'è un motivo che non puoi semplicemente usare (selected-window)qui?
— Aaron Harris,

@AaronHarris: non l'ho provato; Avevo (leggermente) adattato una risposta da un altro post che utilizzava questo meccanismo. Fai un tentativo e vedi se funziona.
— Dan

@Dan: Sì, funziona. Ero solo un po 'preoccupato che una situazione d'angolo potesse farla esplodere. E grazie per quella funzione, a proposito. Fa esattamente quello che voglio che faccia, e non credo che sarei stato in grado di articolare questo che è quello che volevo prima di vedere questa domanda.
— Aaron Harris,

Risposte:


4

Sospiro. Ho trovato una "soluzione", ma è brutta che richiede la sovrascrittura di una orgfunzione esistente . Preferirei uno che non richiede la modifica del orgcodice sorgente, ma sto inserendo qui i risultati del mio scavo archeologico nel caso in cui qualcun altro possa utilizzarlo.

Come ho notato in passato con altre orgfunzioni, org-modeè piuttosto supponente su come gestisce Windows.

Sepolto in profondità nel codice sorgente di org-todoè una chiamata alla funzione org-fast-todo-selection. Quella funzione, a sua volta, chiama org-switch-to-buffer-other-window, il cui docstring legge, in parte:

Passa al buffer in una seconda finestra sul frame corrente. In particolare, non consentire frame pop-up .

Uh Oh.

Ok, ti ​​mordo: diamo un'occhiata org-switch-to-buffer-other-window. Usa la org-no-popups macro. La sua dotstring recita, in parte:

Sopprime le finestre popup. Associamo alcune variabili a zero intorno a BODY ...

Si scopre che display-buffer-alistè una delle variabili letassociate a nil.

(La testa esplode. )

Alla fine, possiamo convincerlo a non ignorare display-buffer-alistmodificando org-fast-todo-selectione sostituendo la org-switch-to-buffer-other-windowlinea con un semplice vecchio 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)))))))

Potresti usare cl fletqui per ricollegare org-switch-to-buffer-other-window? Mi chiedo se puoi consigliare o avvolgere org-fast-todo-selectioninvece di sovrascriverlo.
— Glucas,

@glucas: buona idea. Ho provato e non è riuscito a farlo funzionare, però.
— Dan

1
@Dan, sono stato in grado di farlo funzionare ridefinendo org-switch-to-buffer-other-windowsemplicemente (switch-to-buffer-other-window args). Ho anche rimosso &restdagli argomenti della funzione.
— sk8ingdom,

3

Di recente ho scoperto come realizzare l'acquisizione in modalità Org in un nuovo frame . Modificare quel codice per usare la tua funzione è piuttosto semplice. Ecco come lo farei:

(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)

Per completezza, ecco la definizione della my/with-advicemacro dall'altra risposta:

(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))))

2

Guardando nella configurazione di qualcun altro , ho trovato un modo per controllare dove *Org Src.*e dove *Org todo*appaiono i buffer. Ora quando premo C-c C-to C-c 'questi buffer vengono visualizzati in una nuova finestra nella parte inferiore del layout della finestra corrente e selezionando uno stato TODO o premendo C-c '( org-edit-src-exit), la configurazione della mia finestra viene ripristinata al layout originale.

Questa soluzione prevede l'utilizzo di grilli e alcuni Elisp:

Passo 1

Scarica shackleda MELPA. Ecco come lo configuro use-packagenel mio file 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))

Le impostazioni importanti qui sono:

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

☞ Fonte

Nota in particolare lo spazio tra "e *Orgsulla linea di fondo. Non ho testato l'impostazione :alignin altre posizioni, ma shacklesembra essere abbastanza flessibile, quindi vale la pena leggere la documentazione e sperimentarla.

Passo 2

Ora org-modeascoltiamo shacklecon un po 'più di Elisp nel nostro file init. Per ottenere *Org Src.*i buffer a seguire shackle-rules:

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

☞ Fonte

Sfortunatamente org-modenon fornisce un'impostazione analoga per i *Org todo*buffer. Questo trucco compensa questo (e probabilmente rende (setq org-src-window-setup 'other-window)superfluo, ma qualcuno più esperto dovrà intervenire):

;; 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))

☞ Fonte

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.