(require 'org-id) (require 'reftex) (require 'gnus) ;; The following lines are always needed. Choose your own keys. (add-to-list 'auto-mode-alist '("\\.\\(org\\|org_archive\\|txt\\)$" . org-mode)) (require 'org) (global-set-key "\C-cl" 'org-store-link) (global-set-key "\C-ca" 'org-agenda) (global-set-key "\C-cb" 'org-iswitchb) (setq-default org-log-done 'time) (setq-default org-agenda-ndays 5) ;; agenda configuration ;; Do not dim blocked tasks (setq org-agenda-dim-blocked-tasks nil) ;; Compact the block agenda view (setq org-agenda-compact-blocks t) ;; Custom agenda command definitions (setq org-agenda-custom-commands (quote (("N" "Notes" tags "NOTE" ((org-agenda-overriding-header "Notes") (org-tags-match-list-sublevels t))) ("h" "Habits" tags-todo "STYLE=\"habit\"" ((org-agenda-overriding-header "Habits") (org-agenda-sorting-strategy '(todo-state-down effort-up category-keep)))) (" " "Agenda" ((agenda "" nil) (tags "REFILE" ((org-agenda-overriding-header "Tasks to Refile") (org-tags-match-list-sublevels nil))) (tags-todo "-CANCELLED/!" ((org-agenda-overriding-header "Stuck Projects") (org-agenda-skip-function 'bh/skip-non-stuck-projects) (org-agenda-sorting-strategy '(category-keep)))) (tags-todo "-HOLD-CANCELLED/!" ((org-agenda-overriding-header "Projects") (org-agenda-skip-function 'bh/skip-non-projects) (org-tags-match-list-sublevels 'indented) (org-agenda-sorting-strategy '(category-keep)))) (tags-todo "-CANCELLED/!NEXT" ((org-agenda-overriding-header (concat "Project Next Tasks" (if bh/hide-scheduled-and-waiting-next-tasks "" " (including WAITING and SCHEDULED tasks)"))) (org-agenda-skip-function 'bh/skip-projects-and-habits-and-single-tasks) (org-tags-match-list-sublevels t) (org-agenda-todo-ignore-scheduled bh/hide-scheduled-and-waiting-next-tasks) (org-agenda-todo-ignore-deadlines bh/hide-scheduled-and-waiting-next-tasks) (org-agenda-todo-ignore-with-date bh/hide-scheduled-and-waiting-next-tasks) (org-agenda-sorting-strategy '(todo-state-down effort-up category-keep)))) (tags-todo "-REFILE-CANCELLED-WAITING-HOLD/!" ((org-agenda-overriding-header (concat "Project Subtasks" (if bh/hide-scheduled-and-waiting-next-tasks "" " (including WAITING and SCHEDULED tasks)"))) (org-agenda-skip-function 'bh/skip-non-project-tasks) (org-agenda-todo-ignore-scheduled bh/hide-scheduled-and-waiting-next-tasks) (org-agenda-todo-ignore-deadlines bh/hide-scheduled-and-waiting-next-tasks) (org-agenda-todo-ignore-with-date bh/hide-scheduled-and-waiting-next-tasks) (org-agenda-sorting-strategy '(category-keep)))) (tags-todo "-REFILE-CANCELLED-WAITING-HOLD/!" ((org-agenda-overriding-header (concat "Standalone Tasks" (if bh/hide-scheduled-and-waiting-next-tasks "" " (including WAITING and SCHEDULED tasks)"))) (org-agenda-skip-function 'bh/skip-project-tasks) (org-agenda-todo-ignore-scheduled bh/hide-scheduled-and-waiting-next-tasks) (org-agenda-todo-ignore-deadlines bh/hide-scheduled-and-waiting-next-tasks) (org-agenda-todo-ignore-with-date bh/hide-scheduled-and-waiting-next-tasks) (org-agenda-sorting-strategy '(category-keep)))) (tags-todo "-CANCELLED+WAITING|HOLD/!" ((org-agenda-overriding-header "Waiting and Postponed Tasks") (org-agenda-skip-function 'bh/skip-stuck-projects) (org-tags-match-list-sublevels nil) (org-agenda-todo-ignore-scheduled t) (org-agenda-todo-ignore-deadlines t))) (tags "-REFILE/" ((org-agenda-overriding-header "Tasks to Archive") (org-agenda-skip-function 'bh/skip-non-archivable-tasks) (org-tags-match-list-sublevels nil)))) nil)))) ; org mode agenda files (setq org-agenda-files (quote ("~/projects/debbugs/debbugs.org" "~/projects/notes/notes.org" "~/projects/notes/refile.org" "~/projects/notes/diary.org" "~/projects/origins_of_life/ool.org" "~/projects/sysadmin/sndservers/sndservers.org" "~/projects/chaim/chaim.org" "~/projects/chaim/papers/gwas_paper_2012/gwas_paper.org" "~/projects/reviews/reviews.org" "~/projects/fh/fh.org"))) (setq org-global-properties '(("Effort_ALL 0 0:10 0:30 1:00 2:00 3:00 4:00 5:00 6:00 7:00"))) (setq org-columns-default-format "%40ITEM(Task) %6Effort{:} %CLOCKSUM %PRIORITY %TODO %13SCHEDULED %13DEADLINE %TAGS") (setq org-default-notes-file "~/projects/notes/notes.org") (setq org-capture-templates ;; mail-specific note template, identified by "m" '(("m" "Mail" entry (file+headline "~/projects/notes/refile.org" "Mail") "* %?\n\n Source: %u, %c\n %i") ("t" "todo" entry (file "~/projects/notes/refile.org") "* TODO %?\n%U\n%a\n" :clock-in t :clock-resume t) ("r" "respond" entry (file "~/projects/notes/refile.org") "* NEXT Respond to %:from on %:subject\nSCHEDULED: %t\n%U\n%a\n" :clock-in t :clock-resume t :immediate-finish t) ("n" "note" entry (file "~/projects/notes/refile.org") "* %? :NOTE:\n%U\n%a\n" :clock-in t :clock-resume t) ("s" "schedule" entry (file "~/projects/notes/refile.org") "* %? \n%^{scheduled:}t\n%U\n%a\n" :clock-in t :clock-resume t) ("j" "Journal" entry (file+datetree "~/projects/notes/diary.org") "* %?\n%U\n" :clock-in t :clock-resume t) ("w" "org-protocol" entry (file "~/projects/notes/refile.org") "* TODO Review %c\n%U\n" :immediate-finish t) ("M" "Meeting" entry (file "~/projects/notes/refile.org") "* MEETING with %? :MEETING:\n%U" :clock-in t :clock-resume t) ("p" "Phone call" entry (file "~/projects/notes/refile.org") "* PHONE %? :PHONE:\n%U" :clock-in t :clock-resume t) ("J" "job" entry (file "~/projects/notes/refile.org") "* TODO Apply for %a%? :job:\nSCHEDULED: %(format-time-string \"<%Y-%m-%d %a 17:00-17:30>\")\n%U\n" :clock-in t :clock-resume t) ("h" "Habit" entry (file "~/projects/notes/refile.org") "* NEXT %?\n%U\n%a\nSCHEDULED: %(format-time-string \"<%Y-%m-%d %a .+1d/3d>\")\n:PROPERTIES:\n:STYLE: habit\n:REPEAT_TO_STATE: NEXT\n:END:\n") ) ) ;; Remove empty LOGBOOK drawers on clock out (defun bh/remove-empty-drawer-on-clock-out () (interactive) (save-excursion (beginning-of-line 0) (org-remove-empty-drawer-at "LOGBOOK" (point)))) (defun my/org-add-id () (interactive) (save-excursion (if (org-current-level) () (forward-char 1) ) (org-id-get-create) ) ) ; org mode configuration from http://doc.norang.ca/org-mode.html ;; Custom Key Bindings (global-set-key (kbd "") 'org-agenda) (global-set-key (kbd "") 'bh/org-todo) (global-set-key (kbd "") 'bh/widen) (global-set-key (kbd "") 'bh/set-truncate-lines) (global-set-key (kbd "") 'org-cycle-agenda-files) (global-set-key (kbd " ") 'bh/show-org-agenda) (global-set-key (kbd " b") 'bbdb) (global-set-key (kbd " c") 'calendar) (global-set-key (kbd " f") 'boxquote-insert-file) (global-set-key (kbd " h") 'bh/hide-other) (global-set-key (kbd " n") 'bh/toggle-next-task-display) (global-set-key (kbd " w") 'widen) ; change the outline mode prefix from C-c @ to C-c C-2 (setq outline-minor-mode-prefix "C-c C-2") (add-hook 'outline-minor-mode-hook (lambda () (local-set-key (kbd "C-c C-2") outline-mode-prefix-map))) (global-set-key (kbd " I") 'bh/punch-in) (global-set-key (kbd " O") 'bh/punch-out) (global-set-key (kbd " o") 'bh/make-org-scratch) (global-set-key (kbd " r") 'boxquote-region) (global-set-key (kbd " s") 'bh/switch-to-scratch) (global-set-key (kbd " t") 'bh/insert-inactive-timestamp) (global-set-key (kbd " T") 'bh/toggle-insert-inactive-timestamp) (global-set-key (kbd " v") 'visible-mode) (global-set-key (kbd " l") 'org-toggle-link-display) (global-set-key (kbd " SPC") 'bh/clock-in-last-task) (global-set-key (kbd "C-") 'previous-buffer) (global-set-key (kbd "M-") 'org-toggle-inline-images) (global-set-key (kbd "C-x n r") 'narrow-to-region) (global-set-key (kbd "C-") 'next-buffer) (global-set-key (kbd "") 'org-clock-goto) (global-set-key (kbd "C-") 'org-clock-in) (global-set-key (kbd "C-s-") 'bh/save-then-publish) (global-set-key (kbd "C-c c") 'org-capture) (defun bh/hide-other () (interactive) (save-excursion (org-back-to-heading 'invisible-ok) (hide-other) (org-cycle) (org-cycle) (org-cycle))) (defun bh/set-truncate-lines () "Toggle value of truncate-lines and refresh window display." (interactive) (setq truncate-lines (not truncate-lines)) ;; now refresh window display (an idiom from simple.el): (save-excursion (set-window-start (selected-window) (window-start (selected-window))))) (defun bh/make-org-scratch () (interactive) (find-file "/tmp/publish/scratch.org") (gnus-make-directory "/tmp/publish")) (defun bh/switch-to-scratch () (interactive) (switch-to-buffer "*scratch*")) (setq org-use-fast-todo-selection t) (setq org-treat-S-cursor-todo-selection-as-state-change nil) (setq org-todo-keywords (quote ((sequence "TODO(t)" "NEXT(n)" "|" "DONE(d)") (sequence "WAITING(w@/!)" "HOLD(h@/!)" "|" "CANCELLED(c@/!)" "PHONE" "MEETING")))) (setq org-todo-keyword-faces (quote (("TODO" :foreground "red" :weight bold) ("NEXT" :foreground "blue" :weight bold) ("DONE" :foreground "forest green" :weight bold) ("WAITING" :foreground "orange" :weight bold) ("HOLD" :foreground "magenta" :weight bold) ("CANCELLED" :foreground "forest green" :weight bold) ("MEETING" :foreground "forest green" :weight bold) ("PHONE" :foreground "forest green" :weight bold)))) (setq org-todo-state-tags-triggers (quote (("CANCELLED" ("CANCELLED" . t)) ("WAITING" ("WAITING" . t)) ("HOLD" ("WAITING") ("HOLD" . t)) (done ("WAITING") ("HOLD")) ("TODO" ("WAITING") ("CANCELLED") ("HOLD")) ("NEXT" ("WAITING") ("CANCELLED") ("HOLD")) ("DONE" ("WAITING") ("CANCELLED") ("HOLD"))))) (add-hook 'org-clock-out-hook 'bh/remove-empty-drawer-on-clock-out 'append) ; add ids on creation of nodes (add-hook 'org-capture-prepare-finalize-hook 'my/org-add-id) ; create function to create headlines in file. This comes from ; http://stackoverflow.com/questions/13340616/assign-ids-to-every-entry-in-org-mode (defun my/org-add-ids-to-headlines-in-file () "Add ID properties to all headlines in the current file which do not already have one." (interactive) (org-map-entries 'org-id-get-create)) ; if we wanted to do this to every buffer, do the following: ; (add-hook 'org-mode-hook ; (lambda () ; (add-hook 'before-save-hook 'my/org-add-ids-to-headlines-in-file nil 'local))) ; resolve clocks after 10 minutes of idle; use xprintidle ; (setq org-clock-idle-time 10) ; (setq org-clock-x11idle-program-name "xprintidle") ; this is from http://doc.norang.ca/org-mode.html#Capture ; use C-M-r for org mode capture (global-set-key (kbd "C-M-r") 'org-capture) ; Targets include this file and any file contributing to the agenda - up to 9 levels deep (setq org-refile-targets (quote ((nil :maxlevel . 9) (org-agenda-files :maxlevel . 9)))) ; Use full outline paths for refile targets - we file directly with IDO (setq org-refile-use-outline-path t) ; Targets complete directly with IDO (setq org-outline-path-complete-in-steps nil) ; Allow refile to create parent tasks with confirmation (setq org-refile-allow-creating-parent-nodes (quote confirm)) ; Use IDO for both buffer and file completion and ido-everywhere to t (setq org-completion-use-ido t) (setq ido-everywhere t) (setq ido-max-directory-size 100000) (ido-mode (quote both)) ; Use the current window when visiting files and buffers with ido (setq ido-default-file-method 'selected-window) (setq ido-default-buffer-method 'selected-window) ; Use the current window for indirect buffer display (setq org-indirect-buffer-display 'current-window) ;;;; Refile settings ; Exclude DONE state tasks from refile targets (defun bh/verify-refile-target () "Exclude todo keywords with a done state from refile targets" (not (member (nth 2 (org-heading-components)) org-done-keywords))) (setq org-refile-target-verify-function 'bh/verify-refile-target) ;; ensure that emacsclient will show just the note to be edited when invoked ;; from Mutt, and that it will shut down emacsclient once finished; ;; fallback to legacy behavior when not invoked via org-protocol. (require 'org-protocol) (add-hook 'org-capture-mode-hook 'delete-other-windows) (setq my-org-protocol-flag nil) (defadvice org-capture-finalize (after delete-frame-at-end activate) "Delete frame at remember finalization" (progn (if my-org-protocol-flag (delete-frame)) (setq my-org-protocol-flag nil))) (defadvice org-capture-refile (around delete-frame-after-refile activate) "Delete frame at remember refile" (if my-org-protocol-flag (progn (setq my-org-protocol-flag nil) ad-do-it (delete-frame)) ad-do-it) ) (defadvice org-capture-kill (after delete-frame-at-end activate) "Delete frame at remember abort" (progn (if my-org-protocol-flag (delete-frame)) (setq my-org-protocol-flag nil))) (defadvice org-protocol-capture (before set-org-protocol-flag activate) (setq my-org-protocol-flag t)) (defadvice org-insert-todo-heading (after dla/create-id activate) (org-id-get-create) ) ;; org modules (add-to-list 'org-modules 'org-habit) ; this comes from http://upsilon.cc/~zack/blog/posts/2010/02/integrating_Mutt_with_Org-mode/ (defun open-mail-in-mutt (message) "Open a mail message in Mutt, using an external terminal. Message can be specified either by a path pointing inside a Maildir, or by Message-ID." (interactive "MPath or Message-ID: ") (shell-command (format "faf xterm -e \"%s %s\"" (substitute-in-file-name "$HOME/bin/mutt_open") message))) ;; add support for "mutt:ID" links (org-add-link-type "mutt" 'open-mail-in-mutt) (defun my-org-mode-setup () (load-library "reftex") (and (buffer-file-name) (file-exists-p (buffer-file-name)) (progn (reftex-parse-all) (reftex-set-cite-format '((?b . "[[bib:%l][%l-bib]]") (?n . "[[notes:%l][%l-notes]]") (?c . "\\cite{%l}") (?h . "*** %t\n:PROPERTIES:\n:Custom_ID: %l\n:END:\n[[papers:%l][%l xoj]] [[papers-pdf:%l][pdf]]"))) )) (define-key org-mode-map (kbd "C-c )") 'reftex-citation) (define-key org-mode-map (kbd "C-c [") 'reftex-citation) (define-key org-mode-map (kbd "C-c (") 'org-mode-reftex-search) (define-key org-mode-map (kbd "C-c 0") 'reftex-view-crossref) ) (add-hook 'org-mode-hook 'my-org-mode-setup) (defun org-mode-reftex-search () (interactive) (org-open-link-from-string (format "[[notes:%s]]" (first (reftex-citation t))))) (defun open-research-paper (bibtexkey) "Open a paper by bibtex key" (interactive "bibtex key: ") (shell-command (format "%s %s" (substitute-in-file-name "$HOME/bin/bibtex_to_paper") bibtexkey))) (org-add-link-type "papers" 'open-research-paper) (defun open-research-paper-pdf (bibtexkey) "Open a paper pdf by bibtex key" (interactive "bibtex key: ") (shell-command (format "%s -p evince %s" (substitute-in-file-name "$HOME/bin/bibtex_to_paper") bibtexkey))) (org-add-link-type "papers-pdf" 'open-research-paper-pdf) (add-to-list 'org-link-abbrev-alist '("notes" . "~/projects/research/paper_notes.org::#%s")) ; I pretty much always want hiearchical checkboxes (setq org-hierachical-checkbox-statistics nil) ;; stolen from ;; http://www-public.it-sudparis.eu/~berger_o/weblog/2012/03/23/how-to-manage-and-export-bibliographic-notesrefs-in-org-mode/ (defun my-rtcite-export-handler (path desc format) (message "my-rtcite-export-handler is called : path = %s, desc = %s, format = %s" path desc format) (let* ((search (when (string-match "::#?\\(.+\\)\\'" path) (match-string 1 path))) (path (substring path 0 (match-beginning 0)))) (cond ((eq format 'latex) (if (or (not desc) (equal 0 (search "rtcite:" desc))) (format "\\cite{%s}" search) (format "\\cite[%s]{%s}" desc search)))))) (org-add-link-type "rtcite" 'org-bibtex-open 'my-rtcite-export-handler) (setq-default org-mobile-directory "/rzlab.ucr.edu:/sites/dav.donarmstrong.com/root/org/") (setq-default org-directory "/home/don/org-mode/") (setq-default org-mobile-inbox-for-pull "/home/don/org-mode/from-mobile.org") ;; org mode ical export (setq org-icalendar-timezone "America/Los_Angeles") (setq org-icalendar-use-scheduled '(todo-start event-if-todo)) ;; we already add the id manually ;; (setq org-icalendar-store-UID t) ;; org babel support (org-babel-do-load-languages 'org-babel-load-languages '((emacs-lisp . t ) (R . t) (latex . t) (ditaa . t) )) ;; org-babel-by-backend (defmacro org-babel-by-backend (&rest body) `(case (if (boundp 'backend) (org-export-backend-name backend) nil) ,@body)) ;; ;; org latex ;; ;; stolen from http://kieranhealy.org/esk/kjhealy.html ;; (require 'org-latex) ;; ;; Choose either listings or minted for exporting source code blocks. ;; ;; Using minted (as here) requires pygments be installed. To use the ;; ;; default listings package instead, use ;; ;; (setq org-latex-listings t) ;; ;; and change references to "minted" below to "listings" ;; ; (setq org-latex-listings 'minted) ;; ;; ;; default settings for minted code blocks ;; (setq org-latex-minted-options ;; '(;("frame" "single") ;; ("bgcolor" "bg") ; bg will need to be defined in the preamble of your document. It's defined in org-preamble-pdflatex.sty and org-preamble-xelatex.sty below. ;; ("fontsize" "\\small") ;; )) ;; ;; turn off the default toc behavior; deal with it properly in headers to files. ;; (defun org-latex-no-toc (depth) ;; (when depth ;; (format "%% Org-mode is exporting headings to %s levels.\n" ;; depth))) ;; (setq org-latex-format-toc-function 'org-latex-no-toc) (require 'ox-latex) (add-to-list 'org-latex-classes '("memarticle" "\\documentclass[11pt,oneside,article]{memoir}\n" ("\\section{%s}" . "\\section*{%s}") ("\\subsection{%s}" . "\\subsection*{%s}") ("\\subsubsection{%s}" . "\\subsubsection*{%s}") ("\\paragraph{%s}" . "\\paragraph*{%s}") ("\\subparagraph{%s}" . "\\subparagraph*{%s}"))) (setq org-beamer-outline-frame-options "") (require 'ox-beamer) (add-to-list 'org-latex-classes '("beamer" "\\documentclass[ignorenonframetext]{beamer} [NO-DEFAULT-PACKAGES] [PACKAGES] [EXTRA]" ("\\section{%s}" . "\\section*{%s}") ("\\subsection{%s}" . "\\subsection*{%s}") ("\\subsubsection{%s}" . "\\subsubsection*{%s}") ("\\paragraph{%s}" . "\\paragraph*{%s}") ("\\subparagraph{%s}" . "\\subparagraph*{%s}"))) (add-to-list 'org-latex-classes '("membook" "\\documentclass[11pt,oneside]{memoir}\n" ("\\chapter{%s}" . "\\chapter*{%s}") ("\\section{%s}" . "\\section*{%s}") ("\\subsection{%s}" . "\\subsection*{%s}") ("\\subsubsection{%s}" . "\\subsubsection*{%s}"))) (add-to-list 'org-latex-classes '("letter" "\\documentclass[11pt]{letter} [NO-DEFAULT-PACKAGES] [PACKAGES] [EXTRA]" ("\\section{%s}" . "\\section*{%s}") ("\\subsection{%s}" . "\\subsection*{%s}") ("\\subsubsection{%s}" . "\\subsubsection*{%s}") ("\\paragraph{%s}" . "\\paragraph*{%s}") ("\\subparagraph{%s}" . "\\subparagraph*{%s}"))) ;; Originally taken from Bruno Tavernier: http://thread.gmane.org/gmane.emacs.orgmode/31150/focus=31432 ;; but adapted to use latexmk 4.22 or higher. (setq org-latex-pdf-process '("latexmk -pdflatex=xelatex -bibtex -use-make -pdf %f")) ;; Default packages included in /every/ tex file, latex, pdflatex or xelatex (setq org-latex-default-packages-alist '()) (setq org-latex-packages-alist '(("" "graphicx" t) ("" "fontspec" t) ("" "xunicode" t) ("" "hyperref" t) ("" "url" t) ("" "rotating" t) ("" "longtable" nil) ("" "float" ))) (defun org-create-formula--latex-header () "Return LaTeX header appropriate for previewing a LaTeX snippet." (let ((info (org-combine-plists (org-export--get-global-options (org-export-get-backend 'latex)) (org-export--get-inbuffer-options (org-export-get-backend 'latex))))) (org-latex-guess-babel-language (org-latex-guess-inputenc (org-splice-latex-header org-format-latex-header org-latex-default-packages-alist nil t (plist-get info :latex-header))) info))) ; support ignoring headers in org mode export to latex ; from http://article.gmane.org/gmane.emacs.orgmode/67692 (defadvice org-latex-headline (around my-latex-skip-headlines (headline contents info) activate) (if (member "ignoreheading" (org-element-property :tags headline)) (setq ad-return-value contents) ad-do-it)) ;; keep latex logfiles (setq org-latex-remove-logfiles nil) ;; helper functions (defun bh/is-project-p () "Any task with a todo keyword subtask" (save-restriction (widen) (let ((has-subtask) (subtree-end (save-excursion (org-end-of-subtree t))) (is-a-task (member (nth 2 (org-heading-components)) org-todo-keywords-1))) (save-excursion (forward-line 1) (while (and (not has-subtask) (< (point) subtree-end) (re-search-forward "^\*+ " subtree-end t)) (when (member (org-get-todo-state) org-todo-keywords-1) (setq has-subtask t)))) (and is-a-task has-subtask)))) (defun bh/is-project-subtree-p () "Any task with a todo keyword that is in a project subtree. Callers of this function already widen the buffer view." (let ((task (save-excursion (org-back-to-heading 'invisible-ok) (point)))) (save-excursion (bh/find-project-task) (if (equal (point) task) nil t)))) (defun bh/is-task-p () "Any task with a todo keyword and no subtask" (save-restriction (widen) (let ((has-subtask) (subtree-end (save-excursion (org-end-of-subtree t))) (is-a-task (member (nth 2 (org-heading-components)) org-todo-keywords-1))) (save-excursion (forward-line 1) (while (and (not has-subtask) (< (point) subtree-end) (re-search-forward "^\*+ " subtree-end t)) (when (member (org-get-todo-state) org-todo-keywords-1) (setq has-subtask t)))) (and is-a-task (not has-subtask))))) (defun bh/is-subproject-p () "Any task which is a subtask of another project" (let ((is-subproject) (is-a-task (member (nth 2 (org-heading-components)) org-todo-keywords-1))) (save-excursion (while (and (not is-subproject) (org-up-heading-safe)) (when (member (nth 2 (org-heading-components)) org-todo-keywords-1) (setq is-subproject t)))) (and is-a-task is-subproject))) (defun bh/list-sublevels-for-projects-indented () "Set org-tags-match-list-sublevels so when restricted to a subtree we list all subtasks. This is normally used by skipping functions where this variable is already local to the agenda." (if (marker-buffer org-agenda-restrict-begin) (setq org-tags-match-list-sublevels 'indented) (setq org-tags-match-list-sublevels nil)) nil) (defun bh/list-sublevels-for-projects () "Set org-tags-match-list-sublevels so when restricted to a subtree we list all subtasks. This is normally used by skipping functions where this variable is already local to the agenda." (if (marker-buffer org-agenda-restrict-begin) (setq org-tags-match-list-sublevels t) (setq org-tags-match-list-sublevels nil)) nil) (defvar bh/hide-scheduled-and-waiting-next-tasks t) (defun bh/toggle-next-task-display () (interactive) (setq bh/hide-scheduled-and-waiting-next-tasks (not bh/hide-scheduled-and-waiting-next-tasks)) (when (equal major-mode 'org-agenda-mode) (org-agenda-redo)) (message "%s WAITING and SCHEDULED NEXT Tasks" (if bh/hide-scheduled-and-waiting-next-tasks "Hide" "Show"))) (defun bh/skip-stuck-projects () "Skip trees that are not stuck projects" (save-restriction (widen) (let ((next-headline (save-excursion (or (outline-next-heading) (point-max))))) (if (bh/is-project-p) (let* ((subtree-end (save-excursion (org-end-of-subtree t))) (has-next )) (save-excursion (forward-line 1) (while (and (not has-next) (< (point) subtree-end) (re-search-forward "^\\*+ NEXT " subtree-end t)) (unless (member "WAITING" (org-get-tags-at)) (setq has-next t)))) (if has-next nil next-headline)) ; a stuck project, has subtasks but no next task nil)))) (defun bh/skip-non-stuck-projects () "Skip trees that are not stuck projects" ;; (bh/list-sublevels-for-projects-indented) (save-restriction (widen) (let ((next-headline (save-excursion (or (outline-next-heading) (point-max))))) (if (bh/is-project-p) (let* ((subtree-end (save-excursion (org-end-of-subtree t))) (has-next )) (save-excursion (forward-line 1) (while (and (not has-next) (< (point) subtree-end) (re-search-forward "^\\*+ NEXT " subtree-end t)) (unless (member "WAITING" (org-get-tags-at)) (setq has-next t)))) (if has-next next-headline nil)) ; a stuck project, has subtasks but no next task next-headline)))) (defun bh/skip-non-projects () "Skip trees that are not projects" ;; (bh/list-sublevels-for-projects-indented) (if (save-excursion (bh/skip-non-stuck-projects)) (save-restriction (widen) (let ((subtree-end (save-excursion (org-end-of-subtree t)))) (cond ((bh/is-project-p) nil) ((and (bh/is-project-subtree-p) (not (bh/is-task-p))) nil) (t subtree-end)))) (save-excursion (org-end-of-subtree t)))) (defun bh/skip-project-trees-and-habits () "Skip trees that are projects" (save-restriction (widen) (let ((subtree-end (save-excursion (org-end-of-subtree t)))) (cond ((bh/is-project-p) subtree-end) ((org-is-habit-p) subtree-end) (t nil))))) (defun bh/skip-projects-and-habits-and-single-tasks () "Skip trees that are projects, tasks that are habits, single non-project tasks" (save-restriction (widen) (let ((next-headline (save-excursion (or (outline-next-heading) (point-max))))) (cond ((org-is-habit-p) next-headline) ((and bh/hide-scheduled-and-waiting-next-tasks (member "WAITING" (org-get-tags-at))) next-headline) ((bh/is-project-p) next-headline) ((and (bh/is-task-p) (not (bh/is-project-subtree-p))) next-headline) (t nil))))) (defun bh/skip-project-tasks-maybe () "Show tasks related to the current restriction. When restricted to a project, skip project and sub project tasks, habits, NEXT tasks, and loose tasks. When not restricted, skip project and sub-project tasks, habits, and project related tasks." (save-restriction (widen) (let* ((subtree-end (save-excursion (org-end-of-subtree t))) (next-headline (save-excursion (or (outline-next-heading) (point-max)))) (limit-to-project (marker-buffer org-agenda-restrict-begin))) (cond ((bh/is-project-p) next-headline) ((org-is-habit-p) subtree-end) ((and (not limit-to-project) (bh/is-project-subtree-p)) subtree-end) ((and limit-to-project (bh/is-project-subtree-p) (member (org-get-todo-state) (list "NEXT"))) subtree-end) (t nil))))) (defun bh/skip-project-tasks () "Show non-project tasks. Skip project and sub-project tasks, habits, and project related tasks." (save-restriction (widen) (let* ((subtree-end (save-excursion (org-end-of-subtree t)))) (cond ((bh/is-project-p) subtree-end) ((org-is-habit-p) subtree-end) ((bh/is-project-subtree-p) subtree-end) (t nil))))) (defun bh/skip-non-project-tasks () "Show project tasks. Skip project and sub-project tasks, habits, and loose non-project tasks." (save-restriction (widen) (let* ((subtree-end (save-excursion (org-end-of-subtree t))) (next-headline (save-excursion (or (outline-next-heading) (point-max))))) (cond ((bh/is-project-p) next-headline) ((org-is-habit-p) subtree-end) ((and (bh/is-project-subtree-p) (member (org-get-todo-state) (list "NEXT"))) subtree-end) ((not (bh/is-project-subtree-p)) subtree-end) (t nil))))) (defun bh/skip-projects-and-habits () "Skip trees that are projects and tasks that are habits" (save-restriction (widen) (let ((subtree-end (save-excursion (org-end-of-subtree t)))) (cond ((bh/is-project-p) subtree-end) ((org-is-habit-p) subtree-end) (t nil))))) (defun bh/skip-non-subprojects () "Skip trees that are not projects" (let ((next-headline (save-excursion (outline-next-heading)))) (if (bh/is-subproject-p) nil next-headline))) ; ;; Resume clocking task when emacs is restarted (org-clock-persistence-insinuate) ;; ;; Show lot of clocking history so it's easy to pick items off the C-F11 list (setq org-clock-history-length 23) ;; Resume clocking task on clock-in if the clock is open (setq org-clock-in-resume t) ;; Change tasks to NEXT when clocking in (setq org-clock-in-switch-to-state 'bh/clock-in-to-next) ;; Separate drawers for clocking and logs (setq org-drawers (quote ("PROPERTIES" "LOGBOOK"))) ;; Save clock data and state changes and notes in the LOGBOOK drawer (setq org-clock-into-drawer t) (setq org-log-into-drawer t) ;; Sometimes I change tasks I'm clocking quickly - this removes clocked tasks with 0:00 duration (setq org-clock-out-remove-zero-time-clocks t) ;; Clock out when moving task to a done state (setq org-clock-out-when-done t) ;; Save the running clock and all clock history when exiting Emacs, load it on startup (setq org-clock-persist t) ;; Do not prompt to resume an active clock (setq org-clock-persist-query-resume nil) ;; Enable auto clock resolution for finding open clocks (setq org-clock-auto-clock-resolution (quote when-no-clock-is-running)) ;; Include current clocking task in clock reports (setq org-clock-report-include-clocking-task t) (defvar bh/keep-clock-running nil) (defun bh/clock-in-to-next (kw) "Switch a task from TODO to NEXT when clocking in. Skips capture tasks, projects, and subprojects. Switch projects and subprojects from NEXT back to TODO" (when (not (and (boundp 'org-capture-mode) org-capture-mode)) (cond ((and (member (org-get-todo-state) (list "TODO")) (bh/is-task-p)) "NEXT") ((and (member (org-get-todo-state) (list "NEXT")) (bh/is-project-p)) "TODO")))) (defun bh/find-project-task () "Move point to the parent (project) task if any" (save-restriction (widen) (let ((parent-task (save-excursion (org-back-to-heading 'invisible-ok) (point)))) (while (org-up-heading-safe) (when (member (nth 2 (org-heading-components)) org-todo-keywords-1) (setq parent-task (point)))) (goto-char parent-task) parent-task))) (defun bh/punch-in (arg) "Start continuous clocking and set the default task to the selected task. If no task is selected set the Organization task as the default task." (interactive "p") (setq bh/keep-clock-running t) (if (equal major-mode 'org-agenda-mode) ;; ;; We're in the agenda ;; (let* ((marker (org-get-at-bol 'org-hd-marker)) (tags (org-with-point-at marker (org-get-tags-at)))) (if (and (eq arg 4) tags) (org-agenda-clock-in '(16)) (bh/clock-in-organization-task-as-default))) ;; ;; We are not in the agenda ;; (save-restriction (widen) ; Find the tags on the current task (if (and (equal major-mode 'org-mode) (not (org-before-first-heading-p)) (eq arg 4)) (org-clock-in '(16)) (bh/clock-in-organization-task-as-default))))) (defun bh/punch-out () (interactive) (setq bh/keep-clock-running nil) (when (org-clock-is-active) (org-clock-out)) (org-agenda-remove-restriction-lock)) (defun bh/clock-in-default-task () (save-excursion (org-with-point-at org-clock-default-task (org-clock-in)))) (defun bh/clock-in-parent-task () "Move point to the parent (project) task if any and clock in" (let ((parent-task)) (save-excursion (save-restriction (widen) (while (and (not parent-task) (org-up-heading-safe)) (when (member (nth 2 (org-heading-components)) org-todo-keywords-1) (setq parent-task (point)))) (if parent-task (org-with-point-at parent-task (org-clock-in)) (when bh/keep-clock-running (bh/clock-in-default-task))))))) (defvar bh/organization-task-id "e22cb8bf-07c7-408b-8f60-ff3aadac95e4") (defun bh/clock-in-organization-task-as-default () (interactive) (org-with-point-at (org-id-find bh/organization-task-id 'marker) (org-clock-in '(16)))) (defun bh/clock-out-maybe () (when (and bh/keep-clock-running (not org-clock-clocking-in) (marker-buffer org-clock-default-task) (not org-clock-resolving-clocks-due-to-idleness)) (bh/clock-in-parent-task))) (add-hook 'org-clock-out-hook 'bh/clock-out-maybe 'append) (require 'org-id) (defun bh/clock-in-task-by-id (id) "Clock in a task by id" (org-with-point-at (org-id-find id 'marker) (org-clock-in nil))) (defun bh/clock-in-last-task (arg) "Clock in the interrupted task if there is one Skip the default task and get the next one. A prefix arg forces clock in of the default task." (interactive "p") (let ((clock-in-to-task (cond ((eq arg 4) org-clock-default-task) ((and (org-clock-is-active) (equal org-clock-default-task (cadr org-clock-history))) (caddr org-clock-history)) ((org-clock-is-active) (cadr org-clock-history)) ((equal org-clock-default-task (car org-clock-history)) (cadr org-clock-history)) (t (car org-clock-history))))) (widen) (org-with-point-at clock-in-to-task (org-clock-in nil)))) ; allow for zero-width-space to be a break in regexp too (setcar org-emphasis-regexp-components "​ [:space:] \t('\"{") (setcar (nthcdr 1 org-emphasis-regexp-components) "​ [:space:]- \t.,:!?;'\")}\\") (org-set-emph-re 'org-emphasis-regexp-components org-emphasis-regexp-components)