Jak kontrolować, gdzie wyświetla się bufor słów kluczowych org todo?

9

P : Jak mogę kontrolować, gdzie orgpojawia się bufor słów kluczowych do zrobienia?

Wprowadzenie todosłowa kluczowego za pomocą C-c C-t( org-todo) otwiera nowy bufor z opcjami słowa kluczowego, a następnie zamyka go ponownie po wybraniu. Na razie w porządku. Jednak zajmuje to inne okno, co jest mniej dobre, zwłaszcza, że ​​tak naprawdę wystarczy wyświetlić wiersz lub dwa ze słowami kluczowymi.

Tak więc, w następującym układzie, kliknięcie C-c C-tw lewym oknie ( some-org-buffer) otworzy się *Org todo*w prawym oknie:

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

Zamiast tego chciałbym, aby małe okienko wyskoczyło jako podział pionowy, jak poniżej:

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

Cribing z tej odpowiedzi , napisałem funkcję, aby umieścić w 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))

To jednak nie działa. Westchnienie. Co zrobiłem źle z display-buffer-alist? Co więcej, jak sprawić, todoby bufor słów kluczowych pojawiał się tam, gdzie chcę?

Dan
źródło
Nie jest to odpowiedź na twoje pytanie, ale możesz rozważyć modyfikację, org-switch-to-buffer-other-windowaby robić to, co chcesz - możesz stworzyć warunek, który zrobi co chcesz.
prawnik
@lawlist: dzięki, przekopałem się i dowiedziałem o org-switch-to-buffer-other-windowcałej masie innych brzydkich orgwnętrzności. Zobacz odpowiedź na haniebne „rozwiązanie”.
Dan
Włączając to wszystko do moich .emacs, przyjrzałem się bliżej twojej funkcji pozycjonowania i mam wrażenie, że coś pomijam w twojej definicji win. Czy istnieje powód, dla którego nie możesz po prostu (selected-window)tutaj skorzystać ?
Aaron Harris,
@AaronHarris: nie próbowałem; (Lekko) zaadaptowałem odpowiedź z innego postu, który używał tego mechanizmu. Daj mu szansę i sprawdź, czy to działa.
Dan
@Dan: Tak, działa. Trochę się martwiłem, że jakaś sytuacja w narożniku sprawi, że wybuchnie. I dzięki za tę funkcję, btw. Robi dokładnie to, co chcę, i nie sądzę, bym był w stanie stwierdzić, że tego właśnie chciałem, zanim zobaczyłem to pytanie.
Aaron Harris,

Odpowiedzi:

4

Westchnienie. Znalazłem „rozwiązanie”, ale jest to brzydkie, które wymaga zastąpienia istniejącej orgfunkcji. Wolałbym taki, który nie wymaga modyfikacji orgkodu źródłowego, ale umieszczam tutaj wyniki mojego wykopaliska archeologicznego na wypadek, gdyby ktokolwiek mógł go użyć.

Jak zauważyłem w przeszłości z innymi orgfunkcjami, jestem org-moderaczej przekonany o tym, jak obsługuje okna.

Głęboko w kodzie źródłowym org-todoznajduje się wywołanie funkcji org-fast-todo-selection. Ta funkcja z kolei wywołuje org-switch-to-buffer-other-window, której dokumentacja brzmi, po części:

Przełącz na bufor w drugim oknie bieżącej ramki. W szczególności nie zezwalaj na wyskakujące ramki .

O o.

Dobra, ugryzę: spójrzmy org-switch-to-buffer-other-window. Używa org-no-popups makra. Jego dokumentacja brzmi częściowo:

Pomiń okna wyskakujące. Powiązajmy niektóre zmienne do zera wokół BODY ...

Okazuje się, że display-buffer-alistjest to jedna ze zmiennych letzwiązanych z nil.

( Głowa eksploduje. )

Ostatecznie możemy sprawić, że nie będzie ignorować display-buffer-alist, edytując org-fast-todo-selectioni zastępując org-switch-to-buffer-other-windowwiersz zwykłym starym 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
źródło
Czy możesz użyć cl flettutaj, aby ponownie powiązać org-switch-to-buffer-other-window? Zastanawiasz się, czy możesz doradzić lub w inny sposób zawinąć, org-fast-todo-selectionzamiast nadpisać.
glucas
@glucas: dobry pomysł. Próbowałem tego i nie mogłem go uruchomić.
Dan
1
@ Dan, udało mi się sprawić, by zadziałało, zmieniając definicję org-switch-to-buffer-other-windowna just (switch-to-buffer-other-window args). Usunąłem również &restz argumentów funkcji.
sk8ingdom
3

Ostatnio wymyśliłem, jak zrobić przechwytywanie w trybie Org w nowej ramce . Zmodyfikowanie tego kodu w celu użycia funkcji jest dość proste. Oto jak bym to zrobił:

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

Dla kompletności, oto definicja my/with-advicemakra z drugiej odpowiedzi:

(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
źródło
2

Patrząc na czyjąś konfigurację , znalazłem sposób na kontrolowanie gdzie *Org Src.*i gdzie *Org todo*pojawiają się bufory. Teraz, gdy uderzę C-c C-tlub C-c 'bufory te wyświetlają się w nowym oknie u dołu mojego bieżącego układu okna, a wybranie stanu TODO lub naciśnięcie C-c '( org-edit-src-exit) przywraca pierwotny układ mojego okna.

To rozwiązanie wymaga użycia szekli i niektórych Elisp:

Krok 1

Pobierz shacklez MELPA. Oto jak to skonfigurowałem use-packagew moim pliku 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))

Ważne ustawienia to:

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

Źródło

Zwróć uwagę zwłaszcza na odstęp między "i *Orgw dolnej linii. Nie testowałem ustawień :alignw innych lokalizacjach, ale shacklewydaje się być dość elastyczny, więc warto przeczytać dokumentację i eksperymentować z nią.

Krok 2

Teraz org-modesłuchamy shacklez trochę więcej Elisp w naszym pliku init. Aby uzyskać *Org Src.*bufory do śledzenia shackle-rules:

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

Źródło

Niestety org-modenie zapewnia analogicznego ustawienia *Org todo*buforów. Ten hack to rekompensuje (i prawdopodobnie sprawia (setq org-src-window-setup 'other-window), że zbędne, ale ktoś bardziej kompetentny będzie musiał wejść):

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

Źródło

Tirocinium
źródło