Wie kann man steuern, wo der Schlüsselwortpuffer der Organisation angezeigt wird?

9

F : Wie kann ich steuern, wo der orgAufgabenschlüsselpuffer angezeigt wird?

Wenn Sie ein todoSchlüsselwort mit C-c C-t( org-todo) eingeben, wird ein neuer Puffer mit den Schlüsselwortoptionen geöffnet und nach Auswahl eines Schlüsselworts wieder geschlossen. So weit, ist es gut. Es übernimmt jedoch ein anderes Fenster, was weniger gut ist, zumal es wirklich nur ein oder zwei Zeilen mit den Schlüsselwörtern anzeigen muss.

Bei folgendem Layout wird das Drücken C-c C-tim linken Fenster ( some-org-buffer) *Org todo*im rechten Fenster geöffnet :

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

Stattdessen möchte ich ein kleines Fenster als vertikale Teilung wie folgt anzeigen lassen:

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

Ausgehend von dieser Antwort schrieb ich eine Funktion, um Folgendes einzufügen 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))

Dies funktioniert jedoch nicht. Seufzer. Was habe ich falsch gemacht mit dem display-buffer-alist? Genauer gesagt, wie kann ich meinen todoKeyword-Puffer dort anzeigen lassen, wo ich ihn haben möchte?

Dan
quelle
Keine Antwort auf Ihre Frage, aber Sie können eine Änderung in Betracht ziehen, um das org-switch-to-buffer-other-windowzu tun, was Sie wollen. Sie können eine Bedingung erstellen, die alles tut, was Sie wollen.
Lawlist
@lawlist: danke, ich habe mich umgegraben und etwas über org-switch-to-buffer-other-windoweine ganze Reihe anderer hässlicher orgInnereien herausgefunden. Siehe Antwort für die schmachvolle "Lösung".
Dan
Während ich all dies in meine .emacs einbezog, habe ich mir Ihre Positionierungsfunktion genau angesehen und ich habe das Gefühl, dass mir etwas in Bezug auf Ihre Definition von fehlt win. Gibt es einen Grund, den Sie hier nicht einfach verwenden können (selected-window)?
Aaron Harris
@ AaronHarris: habe es nicht versucht; Ich hatte (leicht) eine Antwort aus einem anderen Beitrag angepasst, der diesen Mechanismus verwendete. Probieren Sie es aus und sehen Sie, ob es funktioniert.
Dan
@ Dan: Ja, es funktioniert. Ich war nur ein wenig besorgt, dass eine Situation in einem Eckfall dazu führen würde, dass es explodiert. Und danke für diese Funktion, übrigens. Es macht genau das, was ich will, und ich glaube nicht, dass ich hätte artikulieren können, dass ich das wollte, bevor ich diese Frage sah.
Aaron Harris

Antworten:

4

Seufzer. Ich habe eine "Lösung" gefunden, aber es ist eine hässliche, bei der eine vorhandene orgFunktion überschrieben werden muss. Ich würde einen bevorzugen, der keine Änderung des orgQuellcodes erfordert , aber die Ergebnisse meiner archäologischen Ausgrabung hier einfüge, falls jemand anderes ihn verwenden kann.

Wie ich in der Vergangenheit bei anderen orgFunktionen bemerkt habe , org-modeist eher eine Meinung darüber, wie es mit Fenstern umgeht.

Tief im Quellcode von org-todoist ein Aufruf der Funktion vergraben org-fast-todo-selection. Diese Funktion ruft wiederum Aufrufe auf org-switch-to-buffer-other-window, deren Dokumentzeichenfolge teilweise lautet:

Wechseln Sie in einem zweiten Fenster des aktuellen Frames zum Puffer. Lassen Sie insbesondere keine Popup-Frames zu .

Oh oh.

Okay, ich werde beißen: lass uns schauen org-switch-to-buffer-other-window. Es verwendet das org-no-popups Makro. Die Dokumentation lautet teilweise:

Popup-Fenster unterdrücken. Lassen Sie einige Variablen um BODY an Null binden ...

Es stellt sich heraus, dass dies display-buffer-alisteine der Variablen ist, an die letgebunden ist nil.

( Kopf explodiert. )

Letztendlich können wir es schaffen, das nicht zu ignorieren, display-buffer-alistindem wir org-fast-todo-selectiondie org-switch-to-buffer-other-windowZeile bearbeiten und durch einfache alte ersetzen 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
quelle
Könnten Sie cl flethier verwenden, um erneut zu binden org-switch-to-buffer-other-window? Ich frage mich, ob Sie raten oder auf andere Weise einpacken können, org-fast-todo-selectionanstatt es zu überschreiben.
Glucas
@ Glucas: gute Idee. Versuchte es und konnte es nicht zum Laufen bringen.
Dan
1
@ Dan, ich konnte dies zum Laufen bringen, indem ich es org-switch-to-buffer-other-windoweinfach neu definierte (switch-to-buffer-other-window args). Ich habe auch &restaus den Funktionsargumenten entfernt.
Sk8ingdom
3

Ich habe kürzlich herausgefunden, wie man im Org-Modus in einem neuen Frame erfasst . Das Ändern dieses Codes zur Verwendung Ihrer Funktion ist ziemlich einfach. So würde ich es machen:

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

Der Vollständigkeit halber hier die Definition des my/with-adviceMakros aus der anderen Antwort:

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

In der Konfiguration eines anderen habe ich einen Weg gefunden, um zu steuern, wo *Org Src.*und *Org todo*Puffer angezeigt werden. Wenn ich jetzt drücke C-c C-toder C-c 'diese Puffer in einem neuen Fenster am unteren Rand meines aktuellen Fensterlayouts angezeigt werden und wenn Sie einen TODO-Status auswählen oder C-c '( org-edit-src-exit) drücken, wird meine Fensterkonfiguration auf das ursprüngliche Layout zurückgesetzt.

Diese Lösung beinhaltet die Verwendung von Schäkel und etwas Elisp:

Schritt 1

Download shacklevon MELPA. So richte ich es use-packagein meiner Init-Datei ein:

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

Die wichtigen Einstellungen hier sind:

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

Quelle

Beachten Sie insbesondere den Abstand zwischen "und *Orgin der unteren Zeile. Ich habe die Einstellung :alignan anderen Orten nicht getestet , shacklescheint aber ziemlich flexibel zu sein. Es lohnt sich also, die Dokumentation zu lesen und damit zu experimentieren.

Schritt 2

Jetzt org-modehören wir uns noch shackleetwas Elisp in unserer Init-Datei an. So erhalten Sie *Org Src.*Puffer, die folgen shackle-rules:

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

Quelle

Bietet leider org-modekeine analoge Einstellung für *Org todo*Puffer. Dieser Hack macht das wieder wett (und macht ihn wahrscheinlich (setq org-src-window-setup 'other-window)überflüssig, aber jemand, der sich besser auskennt, muss sich einschalten):

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

Quelle

Tirocinium
quelle