如何控制org todo关键字缓冲区的显示位置?


9

:如何控制orgtodo关键字缓冲区的显示位置?

todo使用C-c C-torg-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:还没有尝试过;我(轻轻地)改编了使用该机制的另一篇文章的答案。试一试,看看是否有效。

@丹:是的,它的工作原理。我只是有点担心某些极端情况会使其爆炸。并感谢您的功能,顺便说一句。它确实可以实现我想要的功能,而且我认为在看到这个问题之前我还无法明确地表明那是我想要的。
亚伦·哈里斯

Answers:


4

叹。我找到了一个“解决方案”,但这是一个丑陋的解决方案,需要覆盖现有org功能。我希望不需要修改org源代码的代码,但是我把考古挖掘的结果放在这里,以防其他人可以使用它。

正如我过去在使用其他org功能时 所注意到的那样,我org-mode对它如何处理窗口持谨慎态度。

深埋在的源代码中org-todo是对该函数的调用org-fast-todo-selection。该函数依次调用 org-switch-to-buffer-other-window,其文档字符串部分读取:

切换到当前帧的第二个窗口中的缓冲区。特别是,不允许弹出框

哦哦

好吧,我咬一口:让我们看看 org-switch-to-buffer-other-window。它使用org-no-popups 宏。其文档字符串部分读取:

禁止弹出窗口。 让一些变量绑定到 BODY附近...

原来,这display-buffer-alistlet-bound绑定到的变量之一 nil

头爆炸。

最终,我们可以通过编辑该行并将其替换为plain old 来使其忽略 :display-buffer-alistorg-fast-todo-selectionorg-switch-to-buffer-other-windowswitch-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)))))))

您可以flet在这里使用cl 重新绑定org-switch-to-buffer-other-window吗?想知道您是否可以建议或以其他方式包装org-fast-todo-selection而不是覆盖它。
glucas

@glucas:好主意。尝试过,但无法正常工作。

1
@Dan,通过重新定义org-switch-to-buffer-other-window为just ,我可以使它起作用(switch-to-buffer-other-window args)。我也&rest从函数参数中删除了。
sk8ingdom '16

3

我最近想出了如何在新框架中进行组织模式捕获。修改该代码以使用您的函数非常简单。这是我的处理方式:

(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-tC-c '这些缓冲区显示在当前窗口布局底部的新窗口中时,选择TODO状态或单击C-c 'org-edit-src-exit)将窗口配置恢复为其原始布局。

此解决方案涉及使用卸扣和一些Elisp:

步骤1

shackle从MELPA 下载。这是我use-package在初始化文件中进行设置的方法:

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

现在,我们在init文件中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))

资料来源

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.