Como controlar onde o buffer de palavras-chave da organização todo é exibido?

9

P : como posso controlar onde o orgbuffer de palavras-chave todo aparece?

A inserção de uma todopalavra - chave com C-c C-t( org-todo) abre um novo buffer com as opções de palavra-chave e o fecha novamente depois que eu seleciono um. Por enquanto, tudo bem. No entanto, ele assume outra janela, o que é menos bom, especialmente porque ele realmente precisa exibir apenas uma ou duas linhas com as palavras-chave.

Portanto, com o seguinte layout, pressionar C-c C-tenquanto estiver na janela esquerda ( some-org-buffer) será aberto *Org todo*na janela direita:

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

Em vez disso, eu gostaria que uma pequena janela fosse exibida como uma divisão vertical, como abaixo:

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

Partindo dessa resposta , escrevi uma função para inserir 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))

No entanto, isso não funciona. Suspiro. O que eu fiz de errado com o display-buffer-alist? Mais exatamente, como faço para que meu todobuffer de palavras-chave seja exibido onde eu quero?

Dan
fonte
Não é uma resposta para sua pergunta, mas você pode querer modificar org-switch-to-buffer-other-windowpara fazer o que deseja - você pode criar uma condição que faça o que quiser.
lawlist
@lawlist: obrigado, eu procurei e descobri org-switch-to-buffer-other-windowum monte de outras orgentranhas feias . Veja a resposta para a "solução" ignominiosa.
Dan
Ao incorporar tudo isso ao meu .emacs, examinei atentamente sua função de posicionamento e sinto que estou perdendo algo em relação à sua definição de win. Existe um motivo para você não poder usar apenas (selected-window)aqui?
Aaron Harris
@ AaronHarris: não tentei; Eu (levemente) adaptei uma resposta de um post diferente que usava esse mecanismo. Dê uma chance e veja se funciona.
Dan
@ Dan: Sim, funciona. Eu estava apenas um pouco preocupado que alguma situação de esquina pudesse causar uma explosão. E obrigado por essa função, btw. Faz exatamente o que eu quero que faça, e acho que não seria capaz de articular que era isso que eu queria antes de ver essa pergunta.
Aaron Harris

Respostas:

4

Suspiro. Eu encontrei uma "solução", mas é feia e exige a substituição de uma orgfunção existente . Eu preferiria um que não requer modificação do orgcódigo fonte, mas estou colocando aqui os resultados da minha escavação arqueológica, caso alguém possa usá-lo.

Como notei no passado com outras orgfunções, org-modeé bastante opinativo sobre como ele lida com o Windows.

Enterrado profundamente no código fonte de org-todoestá uma chamada para a função org-fast-todo-selection. Essa função, por sua vez, chama org-switch-to-buffer-other-window, cuja doutrina lê, em parte:

Alterne para o buffer em uma segunda janela no quadro atual. Em particular, não permita quadros pop-up .

Uh oh

Ok, eu vou morder: vamos olhar org-switch-to-buffer-other-window. Ele usa a org-no-popups macro. Sua documentação lê, em parte:

Suprimir janelas pop-up. Vamos ligar algumas variáveis ​​para nada em torno de BODY ...

Acontece que essa display-buffer-alisté uma das variáveis letligadas a nil.

(A cabeça explode. )

Por fim, podemos fazer com que não ignore display-buffer-alisteditando org-fast-todo-selectione substituindo a org-switch-to-buffer-other-windowlinha por simples 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
fonte
Você poderia usar cl fletaqui para religar org-switch-to-buffer-other-window? Pensando se você pode aconselhar ou encapsular em org-fast-todo-selectionvez de substituí-lo.
glucas
@glucas: boa ideia. Tentei e não consegui fazê-lo funcionar, no entanto.
Dan
11
@ Dan, eu era capaz de fazer isso funcionar, redefinindo org-switch-to-buffer-other-windowpara apenas (switch-to-buffer-other-window args). Também removi &restos argumentos da função.
Sk8ingdom 27/07/16
3

Recentemente, descobri como fazer a captura no modo Org em um novo quadro . Modificar esse código para usar sua função é bem direto. Aqui está como eu faria isso:

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

Por uma questão de completude, aqui está a definição da my/with-advicemacro da outra resposta:

(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
fonte
2

Procurando na configuração de outra pessoa , encontrei uma maneira de controlar onde *Org Src.*e os *Org todo*buffers aparecem. Agora, quando pressiono C-c C-tou C-c 'esses buffers são exibidos em uma nova janela na parte inferior do meu layout de janela atual, e selecionar um estado TODO ou pressionar h C-c '( org-edit-src-exit) retorna a configuração da minha janela ao seu layout original.

Esta solução envolve o uso de manilha e alguns Elisp:

Passo 1

Download shackledo MELPA. Aqui está como eu o configurei use-packageno meu arquivo 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))

As configurações importantes aqui são:

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

Fonte

Observe especialmente o espaço entre "e *Orgna linha inferior. Não testei a configuração :alignpara outros locais, mas shackleparece ser bastante flexível, por isso vale a pena ler a documentação e experimentar.

Passo 2

Agora org-modeouvimos shacklemais Elisp em nosso arquivo init. Para obter *Org Src.*buffers a seguir shackle-rules:

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

Fonte

Infelizmente org-mode, não fornece uma configuração análoga para *Org todo*buffers. Esse hack compensa isso (e provavelmente torna (setq org-src-window-setup 'other-window)supérfluo, mas alguém mais experiente terá que entrar em cena):

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

tirocínio
fonte