Як контролювати, де відображається буфер ключових слів org todo?


9

Питання : як я можу контролювати, де відображається orgбуфер ключових слів todo?

Введення todoключового слова за допомогою C-c C-t( org-todo) відкриває новий буфер із параметрами ключових слів, а потім знову закриває його після вибору. Все йде нормально. Однак для цього потрібне ще одне вікно, що менш добре, тим більше, що йому дійсно потрібно лише відображати рядок-два з ключовими словами.

Таким чином, при наступному макеті натискання C-c C-tклавіші в ліве вікно ( some-org-buffer) відкриється *Org todo*у правому вікні:

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

Натомість, я хотів би, щоб невелике вікно спливало як вертикальний розкол, як нижче:

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

Скориставшись цією відповіддю , я написав функцію 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))

Однак це не спрацьовує. Зітхнути. Що я зробив неправильно з display-buffer-alist? Більш того, як змусити мій todoбуфер ключових слів з’являтися там, де я його хочу?


Не відповідь на ваше запитання, але, можливо, ви хочете розглянути можливість зміни org-switch-to-buffer-other-windowтого, що ви хочете - ви можете створити умову, яка робить все, що ви хочете.
законник

@lawlist: спасибі, я розкопав і дізнався про org-switch-to-buffer-other-windowцілу купу інших потворних orgнутрощів. Дивіться відповідь на ганебне "рішення".
День

Включаючи все це у свої .emacs, я уважно ознайомився з вашою функцією позиціонування, і мені здається, я щось пропускаю стосовно вашого визначення win. Чи є причина, яку ви не можете просто використати (selected-window)тут?
Аарон Гарріс

@AaronHarris: не пробував; Я (злегка) адаптував відповідь з іншої публікації, яка використовувала цей механізм. Дайте йому постріл і подивіться, чи працює він.
Дан

@Dan: Так, це працює. Я трохи хвилювався, що якась ситуація на кутовому шафі спричинить її вибух. І спасибі за цю функцію, btw. Він робить саме те, що я хочу, і я не думаю, що я міг би сформулювати, що саме цього я хотів, перш ніж побачити це питання.
Аарон Харріс

Відповіді:


4

Зітхнути. Я знайшов "рішення", але це некрасиво, яке вимагає перезаписати існуючу orgфункцію. Я віддаю перевагу такому, який не потребує зміни orgвихідного коду, але я розміщую тут результати мого археологічного копання на випадок, якщо хтось може його використовувати.

Як я помічав у минулому з іншими orgфункціями, org-modeдосить впевнений у тому, як він обробляє вікна.

Похований у глибині вихідного коду org-todo- це виклик функції org-fast-todo-selection. Ця функція, у свою чергу, викликає org-switch-to-buffer-other-window, чий docstring читається, частково:

Перейдіть на буфер у другому вікні поточного кадру. Зокрема, не допускати спливаючих кадрів .

Ой-ой.

Гаразд, я кусаю: давайте подивимось org-switch-to-buffer-other-window. Він використовує org-no-popups макрос. У її документі частково написано:

Придушити спливаючі вікна. Дозвольте прив’язати деякі змінні до нуля навколо BODY ...

Виявляється, display-buffer-alistце одна з змінних let-bound to nil.

( Голова вибухає. )

Зрештою, ми можемо змусити не ігнорувати display-buffer-alistредагування org-fast-todo-selectionта заміну org-switch-to-buffer-other-windowрядка простим старим 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)))))))

Чи можете ви використовувати cl fletтут для повторного перегляду org-switch-to-buffer-other-window? Цікаво, чи можете ви порадити чи іншим способом загортати, org-fast-todo-selectionа не переписувати.
глюкас

@glucas: хороша ідея. Спробував це і не зміг змусити його працювати.
День

1
@Dan, мені вдалося змусити це працювати, переосмислившись org-switch-to-buffer-other-windowна just (switch-to-buffer-other-window args). Я також видалив &restз аргументів функції.
sk8ingdom

3

Нещодавно я зрозумів, як зробити зйомку Org-режиму в новому кадрі . Змінення цього коду для використання вашої функції є досить простим. Ось як я це зробив:

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

Для повноти, ось визначення my/with-adviceмакросу з іншої відповіді:

(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

Заглянувши в чужу конфігурацію , я знайшов спосіб контролювати, де з’являються *Org Src.*і *Org todo*буфери. Тепер, коли я натискаю C-c C-tабо C-c 'ці буфери відображаються в новому вікні в нижній частині мого поточного макета вікна, а при виборі стану TODO або натисканні C-c '( org-edit-src-exit) повертає конфігурацію вікна до початкового макета.

Це рішення включає в себе використання дужку і деякі Elisp:

Крок 1

Завантажити shackleз MELPA. Ось як я це налаштував use-packageу своєму файлі 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))

Тут важливі параметри:

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

Джерело

Особливо відзначте пробіл між "і *Orgв нижній лінії. Я не перевіряв налаштування :alignв інших місцях, але shackleздається досить гнучким, тому варто прочитати документацію та експериментувати з нею.

Крок 2

Тепер ми робимо org-modeслухати shackleз деякими більш Elisp в нашому файлі ініціалізації. Щоб отримати *Org Src.*буфери shackle-rules:

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

Джерело

На жаль org-mode, не передбачено аналогічне налаштування для *Org todo*буферів. Цей злом компенсує це (і, ймовірно, робить (setq org-src-window-setup 'other-window)зайвим, але хтось більш обізнаний повинен буде задзвенити):

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

Джерело

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.