Bagaimana cara mengontrol di mana buffer kata kunci todo ditampilkan?

9

T : bagaimana saya bisa mengontrol di mana orgbuffer kata kunci todo muncul?

Memasukkan todokata kunci dengan C-c C-t( org-todo) membuka buffer baru dengan opsi kata kunci dan kemudian menutupnya lagi setelah saya memilih satu. Sejauh ini bagus. Namun, dibutuhkan jendela lain untuk melakukannya, yang kurang bagus, terutama karena itu benar-benar hanya perlu menampilkan satu atau dua baris dengan kata kunci.

Jadi, dengan tata letak berikut, menekan C-c C-tsaat berada di jendela kiri ( some-org-buffer) akan terbuka *Org todo*di jendela kanan:

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

Sebagai gantinya, saya ingin memiliki jendela kecil yang muncul sebagai pemisahan vertikal, seperti di bawah ini:

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

Merujuk dari jawaban ini , saya menulis sebuah fungsi untuk dimasukkan ke dalam 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))

Namun, itu gagal berfungsi. Mendesah. Apa yang salah dengan saya display-buffer-alist? Lebih penting lagi, bagaimana cara mendapatkan todobuffer kata kunci saya muncul di tempat yang saya inginkan?

Dan
sumber
Bukan jawaban untuk pertanyaan Anda, tetapi Anda mungkin ingin mempertimbangkan memodifikasi org-switch-to-buffer-other-windowuntuk melakukan apa yang Anda inginkan - Anda dapat menciptakan kondisi yang melakukan apa pun yang Anda inginkan.
hukum
@lawlist: terima kasih, aku menggali dan menemukan tentang org-switch-to-buffer-other-windowdan sejumlah orgjeroan jelek lainnya . Lihat jawaban untuk "solusi" yang memalukan.
Dan
Sambil memasukkan semua ini ke dalam .emacs saya, saya memperhatikan fungsi pemosisian Anda, dan saya merasa seperti kehilangan sesuatu mengenai definisi Anda tentang win. Apakah ada alasan mengapa Anda tidak bisa menggunakan di (selected-window)sini saja?
Aaron Harris
@ Harun Harris: belum mencobanya; Saya (secara ringan) mengadaptasi jawaban dari pos berbeda yang menggunakan mekanisme ini. Cobalah dan lihat apakah berhasil.
Dan
@Dan: Ya, berhasil. Saya hanya sedikit khawatir bahwa beberapa situasi kasus sudut akan menyebabkannya meledak. Dan terima kasih untuk fungsinya, btw. Itu melakukan persis apa yang saya ingin lakukan, dan saya tidak berpikir saya akan dapat mengartikulasikan bahwa itulah yang saya inginkan sebelum melihat pertanyaan ini.
Aaron Harris

Jawaban:

4

Mendesah. Saya menemukan "solusi," tapi itu salah satu yang jelek yang membutuhkan menimpa orgfungsi yang ada . Saya lebih suka yang tidak memerlukan modifikasi orgkode sumber, tetapi saya menempatkan hasil penggalian arkeologis saya di sini kalau-kalau ada orang lain yang dapat menggunakannya.

Seperti yang saya perhatikan di masa lalu dengan orgfungsi - fungsi lain , org-modeagak berpendapat tentang bagaimana menangani windows.

Terkubur jauh di dalam kode sumber org-todoadalah panggilan ke fungsi org-fast-todo-selection. Fungsi itu, pada gilirannya, memanggil org-switch-to-buffer-other-window, yang doktringnya berbunyi, sebagian:

Beralih ke buffer di jendela kedua pada frame saat ini. Secara khusus, jangan izinkan bingkai pop-up .

Uh oh.

Oke, saya akan gigit: mari kita lihat org-switch-to-buffer-other-window. Ini menggunakan org-no-popups makro. Dokumennya berbunyi, sebagian:

Menekan jendela sembulan. Biarkan-ikat beberapa variabel hingga nol di sekitar BODY ...

Ternyata itu display-buffer-alistadalah salah satu variabel- letterikat ke nil.

( Kepala meledak. )

Pada akhirnya, kita bisa membuatnya tidak mengabaikan display-buffer-alistdengan mengedit org-fast-todo-selectiondan mengganti org-switch-to-buffer-other-windowbaris dengan yang lama 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
sumber
Bisakah Anda menggunakan cl di fletsini untuk rebind org-switch-to-buffer-other-window? Ingin tahu apakah Anda dapat menyarankan atau membungkus org-fast-todo-selectiondaripada menimpanya.
glucas
@glucas: ide bagus. Mencobanya dan tidak bisa membuatnya bekerja.
Dan
1
@Dan, saya bisa membuatnya bekerja dengan mendefinisikan ulang org-switch-to-buffer-other-windowmenjadi adil (switch-to-buffer-other-window args). Saya juga menghapus &restargumen fungsi.
sk8ingdom
3

Baru-baru ini saya menemukan cara membuat pengambilan mode-Org dalam bingkai baru . Memodifikasi kode untuk menggunakan fungsi Anda cukup mudah. Begini cara saya melakukannya:

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

Demi kelengkapan, inilah definisi my/with-advicemakro dari jawaban lain:

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

Melihat konfigurasi orang lain , saya menemukan cara untuk mengontrol di mana *Org Src.*dan *Org todo*buffer muncul. Sekarang ketika saya menekan C-c C-tatau C-c 'buffer ini ditampilkan di jendela baru di bagian bawah tata letak jendela saya saat ini, dan memilih status TODO atau menekan C-c '( org-edit-src-exit) mengembalikan konfigurasi jendela saya ke tata letak aslinya.

Solusi ini melibatkan penggunaan belenggu dan beberapa Elisp:

Langkah 1

Unduh shackledari MELPA. Inilah cara saya mengaturnya use-packagedi file init saya:

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

Pengaturan penting di sini adalah:

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

Sumber

Perhatikan terutama ruang antara "dan *Orgdi garis bawah. Saya belum menguji pengaturan :alignke lokasi lain, tetapi shackletampaknya cukup fleksibel, jadi ada baiknya membaca dokumentasi dan bereksperimen dengannya.

Langkah 2

Sekarang kita buat org-modemendengarkan shackledengan Elisp lagi di file init kita. Untuk mendapatkan *Org Src.*buffer untuk diikuti shackle-rules:

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

Sumber

Sayangnya org-modetidak menyediakan pengaturan analog untuk *Org todo*buffer. Retasan ini menebus (dan mungkin membuat (setq org-src-window-setup 'other-window)berlebihan, tetapi seseorang yang lebih berpengetahuan harus berpadu):

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

Sumber

hal tak berpengalaman
sumber