Comment contrôler l'emplacement d'affichage du tampon de mots-clés org todo?

9

Q : Comment puis-je contrôler où le orgtampon de mots clés todo apparaît?

La saisie d'un todomot - clé avec C-c C-t( org-todo) ouvre un nouveau tampon avec les options de mot-clé, puis le ferme à nouveau après en avoir sélectionné un. Jusqu'ici tout va bien. Cependant, il reprend une autre fenêtre pour ce faire, ce qui est moins bon, d'autant plus qu'il n'a vraiment besoin d'afficher qu'une ou deux lignes avec les mots clés.

Ainsi, avec la disposition suivante, frapper C-c C-tdans la fenêtre de gauche ( some-org-buffer) s'ouvrira *Org todo*dans la fenêtre de droite:

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

Au lieu de cela, j'aimerais avoir une petite fenêtre pop up comme une division verticale, comme ci-dessous:

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

A partir de cette réponse , j'ai écrit une fonction à mettre dans 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))

Cependant, cela ne fonctionne pas. Soupir. Qu'est-ce que j'ai fait de mal avec le display-buffer-alist? Plus précisément, comment puis-je faire todoapparaître mon tampon de mots clés là où je le souhaite?

Dan
la source
Pas une réponse à votre question, mais vous pouvez envisager de modifier org-switch-to-buffer-other-windowpour faire ce que vous voulez - vous pouvez créer une condition qui fait ce que vous voulez.
lawlist
@lawlist: merci, j'ai fouillé et découvert org-switch-to-buffer-other-windowtout un tas d'autres orgentrailles laides . Voir la réponse pour la "solution" ignominieuse.
Dan
Tout en incorporant tout cela dans mon .emacs, j'ai examiné de près votre fonction de positionnement et j'ai l'impression de manquer quelque chose concernant votre définition de win. Y a-t-il une raison que vous ne pouvez pas simplement utiliser (selected-window)ici?
Aaron Harris
@AaronHarris: je ne l'ai pas essayé; J'avais (légèrement) adapté une réponse d'un autre post qui utilisait ce mécanisme. Essayez-le et voyez si cela fonctionne.
Dan
@Dan: Oui, ça marche. J'étais juste un peu inquiet de voir une situation de coin faire exploser. Et merci pour cette fonction, btw. Il fait exactement ce que je veux qu'il fasse, et je ne pense pas que j'aurais pu dire que c'est ce que je voulais avant de voir cette question.
Aaron Harris

Réponses:

4

Soupir. J'ai trouvé une "solution", mais c'est une laide qui nécessite d'écraser une orgfonction existante . Je préférerais un qui ne nécessite pas de modifier le orgcode source, mais je mets ici les résultats de mes fouilles archéologiques au cas où quelqu'un d'autre pourrait l'utiliser.

Comme je l'ai remarqué dans le passé avec d'autres orgfonctions, org-modeest plutôt d'avis sur la façon dont il gère les fenêtres.

Enterré profondément dans le code source de org-todoest un appel à la fonction org-fast-todo-selection. Cette fonction, à son tour, appelle org-switch-to-buffer-other-window, dont la docstring lit, en partie:

Basculez vers le tampon dans une deuxième fenêtre sur l'image actuelle. En particulier, n'autorisez pas les fenêtres contextuelles .

Euh oh.

D'accord, je vais mordre: regardons org-switch-to-buffer-other-window. Il utilise la org-no-popups macro. Son docstring se lit en partie:

Supprimer les fenêtres contextuelles. Liez certaines variables à zéro autour de BODY ...

Il s'avère que display-buffer-alistc'est l'une des variables letliées à nil.

(La tête explose. )

En fin de compte, nous pouvons l'obtenir pour ne pas ignorer le display-buffer-alisten éditant org-fast-todo-selectionet en remplaçant la org-switch-to-buffer-other-windowligne par plain old 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
la source
Pourriez-vous utiliser cl fletici pour vous relier org-switch-to-buffer-other-window? Vous vous demandez si vous pouvez conseiller ou envelopper autrement org-fast-todo-selectionplutôt que de l'écraser.
glucas
@glucas: bonne idée. J'ai essayé et je n'ai pas réussi à le faire fonctionner.
Dan
1
@Dan, j'ai pu faire fonctionner cela en redéfinissant org-switch-to-buffer-other-windowà juste (switch-to-buffer-other-window args). J'ai également supprimé &restdes arguments de fonction.
sk8ingdom
3

J'ai récemment découvert comment effectuer une capture en mode Org dans un nouveau cadre . Modifier ce code pour utiliser votre fonction est assez simple. Voici comment je le ferais:

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

Par souci d'exhaustivité, voici la définition de la my/with-advicemacro de l'autre réponse:

(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
la source
2

En regardant dans la configuration de quelqu'un d'autre , j'ai trouvé un moyen de contrôler où *Org Src.*et les *Org todo*tampons apparaissent. Maintenant, lorsque je frappe C-c C-tou que C-c 'ces tampons s'affichent dans une nouvelle fenêtre au bas de ma disposition de fenêtre actuelle, et en sélectionnant un état TODO ou en appuyant sur C-c '( org-edit-src-exit), ma configuration de fenêtre reprend sa disposition d'origine.

Cette solution implique l'utilisation de manilles et de certains Elisp:

Étape 1

Téléchargez shackledepuis MELPA. Voici comment je l'ai configuré use-packagedans mon fichier 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))

Les paramètres importants ici sont:

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

Source

Notez en particulier l'espace entre "et *Orgsur la ligne du bas. Je n'ai pas testé la configuration :alignvers d'autres emplacements, mais shacklesemble être assez flexible, il vaut donc la peine de lire la documentation et de l'expérimenter.

Étape 2

Maintenant, nous faisons org-modeécouter shackleavec un peu plus d'Elisp dans notre fichier init. Pour que les *Org Src.*tampons suivent shackle-rules:

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

Source

Malheureusement, org-modene fournit pas de paramètre analogue pour les *Org todo*tampons. Ce hack compense cela (et rend probablement (setq org-src-window-setup 'other-window)superflu, mais quelqu'un de plus compétent devra sonner):

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

Source

tirocinium
la source