lang/org: fix org-capture workflow and org-shackle hacks

This commit is contained in:
Henrik Lissner 2017-02-24 20:00:59 -05:00
parent 2f81ca11a5
commit a446c58846
4 changed files with 90 additions and 81 deletions

View file

@ -348,43 +348,66 @@ the command buffer."
(add-hook! org-load (add-hook! org-load
;; Ensures org-src-edit yields control of its buffer to shackle. (set! :popup
(defun doom*org-src-switch-to-buffer (buffer context) (pop-to-buffer buffer)) '("*Calendar*" :size 0.4 :noselect t)
(advice-add 'org-src-switch-to-buffer :override 'doom*org-src-switch-to-buffer) '(" *Org todo*" :size 5 :noselect t)
'("*Org Note*" :size 10)
'("*Org Select*" :size 20 :noselect t)
'("*Org Links*" :size 5 :noselect t)
'(" *Agenda Commands*" :noselect t)
'("^\\*Org Agenda" :regexp t :size 0.4)
'("*Org Clock*" :noselect t)
'("*Edit Formulas*" :size 10)
'("\\*Org Src" :regexp t :size 15)
'("^\\*Org-Babel" :regexp t :size 0.4)
'("^CAPTURE.*\\.org$" :regexp t :size 20))
;; ...for org-todo, org-link and org-agenda popups ;; Org tries to do its own popup management, causing buffer/window config
(defun doom*org-pop-to-buffer-same-window (&optional buffer-or-name norecord label) ;; armageddon when paired with shackle. To fix this, first we suppress
"Pop to buffer specified by BUFFER-OR-NAME in the selected window." ;; delete-other-windows in org functions:
(display-buffer buffer-or-name)) (defun doom*suppress-delete-other-windows (orig-fn &rest args)
(advice-add 'org-pop-to-buffer-same-window :override 'doom*org-pop-to-buffer-same-window) (cl-flet ((silence (&rest args) (ignore)))
(advice-add 'delete-other-windows :around #'silence)
(unwind-protect
(apply orig-fn args)
(advice-remove 'delete-other-windows #'silence))))
(advice-add 'org-capture-place-template :around #'doom*suppress-delete-other-windows)
(advice-add 'org-agenda :around #'doom*suppress-delete-other-windows)
(advice-add 'org-add-log-note :around #'doom*suppress-delete-other-windows)
;; Tell org-src-edit to open another window, which shackle can intercept.
(setq org-src-window-setup 'other-window)
;; Then, we tell org functions to use pop-to-buffer instead of
;; switch-to-buffer-*. Buffers get handed off to shackle properly this way.
(defun doom*org-switch-to-buffer-other-window (&rest args) (defun doom*org-switch-to-buffer-other-window (&rest args)
(car-safe (pop-to-buffer (car args)))
(mapc (lambda (b)
(let ((buf (if (stringp b) (get-buffer-create b) b)))
(pop-to-buffer buf t t)))
args)))
(advice-add 'org-switch-to-buffer-other-window :override 'doom*org-switch-to-buffer-other-window) (advice-add 'org-switch-to-buffer-other-window :override 'doom*org-switch-to-buffer-other-window)
(defun doom/popup-org-agenda-quit () ;; ...for org-todo, org-link and org-agenda popups
"Necessary to finagle org-agenda into shackle popups & behave on quit." ;; (defun doom*org-pop-to-buffer-same-window (&optional buffer-or-name norecord label)
(interactive) ;; "Pop to buffer specified by BUFFER-OR-NAME in the selected window."
(if org-agenda-columns-active ;; (switch-to-buffer buffer-or-name))
(org-columns-quit) ;; (advice-add 'org-pop-to-buffer-same-window :override 'doom*org-pop-to-buffer-same-window)
(let ((buf (current-buffer)))
(and (not (eq org-agenda-window-setup 'current-window)) ;; (defun doom/popup-org-agenda-quit ()
(not (one-window-p)) ;; "Necessary to finagle org-agenda into shackle popups & behave on quit."
(delete-window)) ;; (interactive)
(kill-buffer buf) ;; (if org-agenda-columns-active
(setq org-agenda-archives-mode nil ;; (org-columns-quit)
org-agenda-buffer nil)))) ;; (let ((buf (current-buffer)))
;; (and (not (eq org-agenda-window-setup 'current-window))
;; (not (one-window-p))
;; (delete-window))
;; (kill-buffer buf)
;; (setq org-agenda-archives-mode nil
;; org-agenda-buffer nil))))
(after! org-agenda (after! org-agenda
(after! evil (after! evil
(evil-define-key* 'motion org-agenda-mode-map (map! :map* org-agenda-mode-map
[escape] 'doom/popup-org-agenda-quit :m [escape] 'doom/popup-org-agenda-quit
(kbd "ESC") 'doom/popup-org-agenda-quit)) :m "ESC" 'doom/popup-org-agenda-quit))
(let ((map org-agenda-mode-map)) (let ((map org-agenda-mode-map))
(define-key map "q" 'doom/popup-org-agenda-quit) (define-key map "q" 'doom/popup-org-agenda-quit)
(define-key map "Q" 'doom/popup-org-agenda-quit)))) (define-key map "Q" 'doom/popup-org-agenda-quit))))

View file

@ -1,31 +1,26 @@
;;; lang/org/+capture.el --- -*- no-byte-compile: t; -*- ;;; lang/org/+capture.el --- -*- no-byte-compile: t; -*-
;; Sets up a sane `org-capture' workflow, wherein the org-capture buffer is ;; Sets up two `org-capture' workflows that I like:
;; opened in a popup frame, and can be invoked from outside Emacs as well.
;; ;;
;; See `+org/capture' ;; 1. The traditional way: invoking `org-capture' directly (or through a
;; command, like :org).
;;
;; 2. Through a org-capture popup frame that is invoked from outside Emacs (the
;; script is below). This lets me open an org-capture box anywhere I can call
;; org-capture.sh, like, say, from qutebrowser or vimperator.
;;
;; #!/usr/bin/env bash
;; emacsclient -c \
;; -F "((name . \"org-capture\") (height . 25) (width . 70))" \
;; --eval "(org-capture nil \"${1:-n}\")"
;;
;; Place this in, say, org-capture.sh somewhere in your $PATH.
(add-hook '+org-init-hook '+org|init-capture t) (add-hook '+org-init-hook '+org|init-capture t)
(defun +org|init-capture () (defun +org|init-capture ()
"Set up a sane `org-capture' workflow." "Set up a sane `org-capture' workflow."
(setq org-default-notes-file +org-quicknote-dir) (setq org-default-notes-file (concat +org-dir "notes.org"))
(require 'org-capture)
(require 'org-protocol)
(set! :popup "*Org Select*" :size 0.4)
(defadvice org-capture (after make-full-window-frame activate)
"If org-capture creates a new frame, this initializes it properly, by
deleting other windows and blanking out the mode-line."
(when (equal "org-capture" (frame-parameter nil 'name))
(setq mode-line-format nil)
(delete-other-windows)))
(defadvice org-capture-finalize (after delete-capture-frame activate)
"Closes the frame once org-capture is done."
(when (equal "org-capture" (frame-parameter nil 'name))
(delete-frame)))
(setq org-capture-templates (setq org-capture-templates
'(;; TODO: New Task (todo) '(;; TODO: New Task (todo)
@ -44,11 +39,30 @@ deleting other windows and blanking out the mode-line."
;; "* %u %?\n%i" :prepend t) ;; "* %u %?\n%i" :prepend t)
("n" "Notes" entry ("n" "Notes" entry
(file+headline org-default-notes-file "Inbox") (file+headline (concat +org-dir "notes.org") "Inbox")
"* %u %?\n%i" :prepend t) "* %u %?\n%i" :prepend t)
;; ("v" "Vocab" entry ;; ("v" "Vocab" entry
;; (file+headline (concat org-directory "topics/vocab.org") "Unsorted") ;; (file+headline (concat org-directory "topics/vocab.org") "Unsorted")
;; "** %i%?\n") ;; "** %i%?\n")
))) ))
;; Allows the Emacs mini-frame (opened from an external shell script to run
;; and clean up properly) if the frame is named "org-capture".
(require 'org-capture)
(require 'org-protocol)
(defun +org*capture-init (&rest _)
"Makes sure the org-capture window is the only window in the frame."
(when (equal "org-capture" (frame-parameter nil 'name))
(setq mode-line-format nil)
(delete-other-windows)))
(advice-add 'org-capture :after '+org*capture-init)
(defun +org|capture-finalize ()
"Closes the frame once org-capture is done."
(when (equal "org-capture" (frame-parameter nil 'name))
(when (and (featurep 'persp-mode) persp-mode)
(+workspace/delete (+workspace-current-name)))
(delete-frame)))
(add-hook 'org-capture-after-finalize-hook '+org|capture-finalize))

View file

@ -1,18 +1,3 @@
;;; lang/org/autoload/capture.el ;;; lang/org/autoload/capture.el
;;;###autoload
(defun +org/capture (&optional template string)
"Run `org-capture' in a new, disposable popup frame."
(interactive)
(let ((org-capture-entry (org-capture-select-template template)))
(cond ((equal org-capture-entry "C")
(find-file (expand-file-name "module-org-notes.el" doom-modules-dir))
(re-search-forward "^\\s-+(setq org-capture-templates" (point-max) t)
(recenter))
((not (equal org-capture-entry "q"))
(let ((frame (make-frame '((name . "org-capture") (height . 15) (width . 80)))))
(with-selected-frame frame
(if string
(org-capture-string string)
(org-capture))))))))

View file

@ -17,17 +17,13 @@
(add-hook 'org-mode-hook '+org|hook) (add-hook 'org-mode-hook '+org|hook)
;; Custom variables ;; Custom variables
(defvar +org-dir "~/work/org/" (defvar +org-dir (expand-file-name "~/work/org/")
"The directory where org files are kept.") "The directory where org files are kept.")
(defvaralias 'org-directory '+org-dir) (defvaralias 'org-directory '+org-dir)
(defvar +org-notes-dir (concat +org-dir "notes") (defvar +org-notes-dir (concat +org-dir "notes")
"The directory where the notes are kept") "The directory where the notes are kept")
(defvar +org-quicknote-dir (concat +org-dir "inbox")
"The directory to store quick notes produced by `doom:org-capture' (individual org files)")
(defvar +org-attachment-dir ".attach/" (defvar +org-attachment-dir ".attach/"
"Where to store attachments (relative to current org file).") "Where to store attachments (relative to current org file).")
@ -59,7 +55,7 @@
(defun +org|update-cookies () (defun +org|update-cookies ()
"Update counts on headlines (\"cookies\")." "Update counts on headlines (\"cookies\")."
(when (file-exists-p buffer-file-name) (when (and buffer-file-name (file-exists-p buffer-file-name))
(org-update-statistics-cookies t))) (org-update-statistics-cookies t)))
(add-hook 'before-save-hook '+org|update-cookies nil t) (add-hook 'before-save-hook '+org|update-cookies nil t)
@ -75,15 +71,6 @@
:keymap (make-sparse-keymap) :keymap (make-sparse-keymap)
:group 'evil-org) :group 'evil-org)
(set! :popup
'(" *Agenda Commands*" :size 30 :noselect t)
'(" *Org todo*" :size 5 :noselect t)
'("*Calendar*" :size 0.4 :noselect t)
'("*Org Links*" :size 5 :noselect t)
'("^\\*Org Agenda.+" :size 0.4 :regexp t)
'("^\\*Org Src .+\\*$" :size 0.4 :regexp t)
'("^\\*Org-Babel.*\\*$" :size 0.4 :regexp t))
(setq-default (setq-default
org-export-coding-system 'utf-8 org-export-coding-system 'utf-8