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.