【问题标题】:Emacs force org-mode capture buffer to open in a new windowEmacs 强制 org-mode 捕获缓冲区在新窗口中打开
【发布时间】:2014-01-17 20:32:52
【问题描述】:

如何强制 org-mode 的捕获缓冲区在新窗口中打开?我试过了

(setq special-display-regexps
    '("^\\*Capture\\*$"))

但它不起作用 - 我暂时看到一个新窗口,然后 org-mode 进行了两个垂直拆分(我正在使用 3 个垂直拆分),并将捕获缓冲区放入正确的拆分中。当我通过C-c C-cC-c C-k 完成时,将恢复原始拆分设置。

【问题讨论】:

  • 不修改一些控制目标窗口的核心捕获函数,你要的很难。如果没有提供其他解决方案,我会看看是否有更简单的解决方案。我已经采用了所有的捕获函数并对其进行了重命名和修改,以删除控制目标并恢复先前存储的窗口配置的内容。
  • 玩了一会儿之后,我想它会像你说的那样。感谢您的评论!
  • 如果您想查看org-capture.el,您可以快速搜索以下条目以更好地了解正在发生的事情:(org-pop-to-buffer-same-window (org-capture-get :buffer)); (org-pop-to-buffer-same-window (get-buffer-create "*Capture*")); (org-capture-put :return-to-wconf (current-window-configuration)); (set-window-configuration (org-capture-get :return-to-wconf))org-pop-to-buffer-same-windoworg-compat.el 中定义。我选择删除所有这些东西并使用with-current-buffer 创建新功能,然后以我自己的方式显示。
  • 感谢您的信息。我去看看。
  • 暂时恢复这个,因为我试图阻止org-capture 修改我的窗口配置。 a),你知道了吗?如果不是,b),您是否只希望 capture 缓冲区在不同的 窗口 中打开而不修改您的三跨设置,或者您是否在询问是否可以在一个新的框架

标签: emacs org-mode


【解决方案1】:

我也喜欢使用许多并排拆分(通常是 4 个——我分布在多个显示器上),所以 org-capture 将 4 个常规窗口变成 2 个非常宽的窗口的行为让我每次头都会爆炸——这往往会让我失去理智。

+---+---+---+---+     +-------+-------+
| 1 | 2 | 3 | 4 | --> |   1   |capture| = head explosion
+---+---+---+---+     +-------+-------+

所以这里有一种方法可以防止org-capture 修改您的窗口配置。

经过一番搜索,似乎没有一种简单的方法可以自定义此行为(或者至少不是一个明显的方法)。跟踪源代码中的函数调用将我们带到org-capture-place-template,它会保存您的原始窗口配置,然后删除其他窗口,然后为您提供两个窗口拆分。当然,当您最终完成捕获时,您稍后会恢复您的窗口配置,但是摆脱“让我们在没有您说的情况下更改您的窗口布局”步骤肯定会很好。

事实证明这很简单。只需在注释掉调用(delete-other-windows) 的单行后重新评估org-capture-place-template

(defun org-capture-place-template ()
  "Insert the template at the target location, and display the buffer."
  (org-capture-put :return-to-wconf (current-window-configuration))
  ;; (delete-other-windows)                ; this is the culprit!
  (org-switch-to-buffer-other-window
   (org-capture-get-indirect-buffer (org-capture-get :buffer) "CAPTURE"))
  (widen)
  (show-all)
  (goto-char (org-capture-get :pos))
  (org-set-local 'org-capture-target-marker
         (point-marker))
  (org-set-local 'outline-level 'org-outline-level)
  (let* ((template (org-capture-get :template))
     (type (org-capture-get :type)))
    (case type
      ((nil entry) (org-capture-place-entry))
      (table-line (org-capture-place-table-line))
      (plain (org-capture-place-plain-text))
      (item (org-capture-place-item))
      (checkitem (org-capture-place-item))))
  (org-capture-mode 1)
  (org-set-local 'org-capture-current-plist org-capture-plist))

啊啊啊。就像org-capture 每次使用它时都在打我的脸,但现在它停止了。


(已编辑:以下是较新版本的 org-mode)

(defun org-capture-place-template (&optional inhibit-wconf-store)
  "Insert the template at the target location, and display the buffer.
When `inhibit-wconf-store', don't store the window configuration, as it
may have been stored before."
  (unless inhibit-wconf-store
    (org-capture-put :return-to-wconf (current-window-configuration)))
  ;(delete-other-windows)
  (org-switch-to-buffer-other-window
   (org-capture-get-indirect-buffer (org-capture-get :buffer) "CAPTURE"))
  (widen)
  (show-all)
  (goto-char (org-capture-get :pos))
  (org-set-local 'org-capture-target-marker
         (point-marker))
  (org-set-local 'outline-level 'org-outline-level)
  (let* ((template (org-capture-get :template))
     (type (org-capture-get :type)))
    (case type
      ((nil entry) (org-capture-place-entry))
      (table-line (org-capture-place-table-line))
      (plain (org-capture-place-plain-text))
      (item (org-capture-place-item))
      (checkitem (org-capture-place-item))))
  (org-capture-mode 1)
  (org-set-local 'org-capture-current-plist org-capture-plist))

【讨论】:

  • 感谢您的回答。我只是将此代码粘贴到缓冲区并对其进行评估,但随后捕获不起作用。它没有破坏我的设置并成功显示Select a capture template,但是当我选择模板时,它在Minibuffer中显示了一堆代码。
  • 从那以后代码似乎有所更改。我从orgmode.org/w/?p=org-mode.git;a=blob_plain;f=lisp/… 复制代码并注释掉相同的(delete-other-windows) 行,它开始正常工作。
  • 我想出了一个alternative version,它应该更能抵抗未来的组织模式代码更改。
  • 可悲的是,我运行了这个并得到一个关于 org-set-local 函数定义为 void 的错误
  • 似乎 org-set-local 不再可用。我也遇到了这个错误,并改用setq-local 修复它。
【解决方案2】:

这是我想出的解决方案。这会导致整个捕获过程发生在单个弹出帧中。

首先,几个辅助函数。

(defun my/get-frame-by-name (fname)
  "If there is a frame with named FNAME, return it, else nil."
  (require 'dash)                       ; For `-some'
  (-some (lambda (frame)
           (when (equal fname (frame-parameter frame 'name))
             frame))
         (frame-list)))

(defun my/display-buffer-in-named-frame (buffer alist)
  "Display BUFFER in frame with specific name.
The name to use is the value associated with the 'named-frame key
in ALIST.  If a frame with that name already exists, use it.
Otherwise, call `display-buffer-in-pop-up-frame' to create it.

If ALIST does not contain the key 'named-frame, use the name of BUFFER."
  (let* ((fname  (or (cdr (assq 'named-frame alist))
                     (buffer-name buffer)))
         (frame  (my/get-frame-by-name fname)))
    (if frame
        (window--display-buffer buffer
                                (frame-selected-window frame)
                                'reuse) 
      (display-buffer-pop-up-frame
       buffer
       (add-to-list 'alist `(pop-up-frame-parameters
                             (name . ,fname)))))))

接下来,安装临时通知的宏。如果你愿意,你可以很容易地内联它。

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

这是主要功能。这个想法是暂时覆盖 Org-mode 正在做的所有我们不想要的事情。这包括 Dan 的回答中提到的 delete-other-windows 调用,以及对 org-switch-to-buffer-other-window 的两次调用,它明确阻止了弹出框。

(defun my/org-capture-in-popout-frame (&optional goto keys)
  "As `org-capture', but do all work in a new frame.

    This function by itself doesn't clean up the frame following
    capture.  To do that, add `my/org-capture-delete-capture-frame'
    to `org-capture-after-finalize-hook'."
  (interactive "P")
  (if goto
      (org-capture goto keys)
    (let ((override  '("\\*Org Select\\*\\|\\*Capture\\*\\|CAPTURE-.*"
                       my/display-buffer-in-named-frame
                       (named-frame . "Capture"))))
      ;; Force all relevant buffers to open in a specific capture frame.
      (add-to-list 'display-buffer-alist override)
      (my/with-advice 
          (;; Make Org-mode respect `display-buffer-alist'.
           (#'org-switch-to-buffer-other-window :override #'pop-to-buffer)
           ;; And stop Org-mode from messing with our window configuration.
           (#'delete-other-windows :override #'ignore))
        (unwind-protect (condition-case err
                            (org-capture goto keys)
                          (error (my/org-capture-delete-capture-frame)
                                 (signal (car err) (cdr err))))
          (setq display-buffer-alist
                (delete override display-buffer-alist)))))))

要在捕获完成后消除帧,请使用此功能:

(defun my/org-capture-delete-capture-frame ()
  "Delete a frame named \"Capture\".
For use in `org-capture-after-finalize-hook' to clean up after
`my/org-capture-in-popout-frame'."
  (let ((frame  (my/get-frame-by-name "Capture")))
    (when frame (delete-frame frame))))

my/capture-in-popout-frame 在提前中止的情况下已经调用了它(例如,在模板选择缓冲区中输入 q 或在捕获模板中输入 C-g 以响应提示)。对于正常完成(包括重新归档)或延迟中止(来自捕获模板的C-c C-k),您需要将其添加到org-capture-after-finalize-hook

(add-hook 'org-capture-after-finalize-hook
          #'my/org-capture-delete-capture-frame)

请注意,这些函数都不会修改对org-capture 的独立调用的工作方式(除非由于某种原因您有一个名为“Capture”的额外框架),因此如果您需要它,您仍然可以获得默认行为特定的捕获。

一个警告:这将不支持多个同时捕获进程。我个人不需要,但如果你需要,我认为添加该功能应该不会太难。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-19
    • 1970-01-01
    • 1970-01-01
    • 2012-07-08
    • 1970-01-01
    • 2014-10-17
    相关资源
    最近更新 更多