summary refs log tree commit diff
path: root/emacs.d/custom/fcuny-org.el
diff options
context:
space:
mode:
authorFranck Cuny <fcuny@twitter.com>2019-10-06 15:11:19 -0700
committerFranck Cuny <fcuny@twitter.com>2019-10-06 15:11:19 -0700
commit7a08b36af4d442fd11e9e4cf14fc1ed507f56e02 (patch)
tree3471496675ea1da5ea27d5b816d216eb94e5e003 /emacs.d/custom/fcuny-org.el
parent[emacs] dropped the :columns information (diff)
downloademacs.d-7a08b36af4d442fd11e9e4cf14fc1ed507f56e02.tar.gz
[org] a lot of changes.
Adding a menu for hydra, to jump quickly to some files.

I'm also adding a few custom commands for the agenda. After that many
experiment, I think this is what I'm missing to be more
efficient. This allows me to ignore completely how the file *looks*
and focus on getting through the tasks.

I'm also adding a few keywords for managing tasks:
- PROJECT is for large tasks (e.g. an epic). This can be transitioned
to PROJECTDONE
- MEETING and NOTES are tasks that are completed, and I use them to
keep track of various things in a project.
Diffstat (limited to '')
-rw-r--r--emacs.d/custom/fcuny-org.el274
1 files changed, 187 insertions, 87 deletions
diff --git a/emacs.d/custom/fcuny-org.el b/emacs.d/custom/fcuny-org.el
index 35d673a..5c15ef6 100644
--- a/emacs.d/custom/fcuny-org.el
+++ b/emacs.d/custom/fcuny-org.el
@@ -6,16 +6,12 @@
 (use-package org
   :after (dash)
   :ensure t
-
   :hook ((org-mode              . visual-line-mode)
          (org-mode              . org-indent-mode)
-         (org-capture-mode-hook . delete-other-windows)
-         (org-mode              . fcuny/org-mode-setup))
-
+         (org-capture-mode-hook . delete-other-windows))
   :bind (("C-c c" . org-capture)
          ("C-c a" . org-agenda)
          ("C-c o" . hydra-org-menu/body))
-
   :config
   (progn ()
     (org-babel-do-load-languages
@@ -24,37 +20,161 @@
        (python . t)
        (emacs-lisp . t))))
 
+  (defhydra hydra-org-menu (:hint nil)
+    "
+^go to              ^    ^action         ^
+^-------------------^    ^---------------^
+_g i_: go to inbox       _s_: save files
+_g p_: go to personal
+_g w_: go to work
+_g n_: go to notes
+"
+    ("g i" (find-file-other-window org-default-inbox-file))
+    ("g p" (find-file-other-window org-default-personal-file))
+    ("g w" (find-file-other-window org-default-work-file))
+    ("g n" (find-file-other-windw org-default-notes-file))
+    ("s" (org-save-all-org-buffers)))
+
   :custom
   ;; cosmetic
   (org-pretty-entities t)
-  (org-startup-indented t)
-  (org-tags-column -120)
+  (org-startup-indented nil)
+  (org-tags-column -97)
+
+  ;;
+  (org-log-done 'time)
+
+  ;; priorities
+  (org-priority-start-cycle-with-default nil) ;; Start one over/under default value.
+  (org-lowest-priority ?D)
+  (org-default-priority ?D) ;; Ensures unset tasks have low priority.
+  (org-priority-faces '((?A . "#ff2600")
+                        (?B . "#ff5900")
+                        (?C . "#ff9200")
+                        (?D . "#747474")))
 
   ;; files
   (org-directory (expand-file-name "~/Documents/notebooks"))
   (org-archive-dir (concat org-directory "/archive/"))
 
-  (org-default-projects-dir (concat org-directory "/projects"))
-  (org-default-personal-dir (concat org-directory "/personal"))
-  (org-default-completed-dir (concat org-directory "/completed"))
-  (org-default-technical-dir (concat org-directory "/technical"))
-
-  (org-default-completed-file nil)
+  (org-default-personal-file (concat org-directory "/personal.org"))
+  (org-default-work-file (concat org-directory "/twitter.org"))
+  (org-default-journal-file (concat org-directory "/journal.org"))
   (org-default-inbox-file (concat org-directory "/inbox.org"))
-  (org-default-tasks-file (concat org-directory "/tasks.org"))
-  (org-default-incubate-file (concat org-directory "/incubate.org"))
-  (org-default-media-file (concat org-directory "/media.org"))
   (org-default-notes-file (concat org-directory "/notes.org"))
 
   ;; how to manage tasks
-  (org-todo-keywords '((sequence "TODO(t)" "DOING(g)" "|" "DONE(d)")
-                       (sequence "|" "CANCELED(c)")))
+  (org-todo-keywords '((sequence "TODO(t)" "STARTED(s)" "DELEGATED(D)" "|" "DONE(d)")
+                       (sequence "|" "MEETING(m)" "NOTE(n)")
+                       (sequence "PROJECT" "|" "PROJECTDONE")
+                       (sequence "SOMEDAY" "|" "CANCELED(c)")))
 
   ;; agenda related
   (org-agenda-start-on-weekday 1)
-  (org-agenda-files `(,org-default-projects-dir
-                      ,org-default-inbox-file
-                      ,org-default-tasks-file))
+  (org-agenda-files `(,org-default-personal-file
+                      ,org-default-work-file))
+
+  (org-agenda-custom-commands
+   (quote
+    (("w" . "Work...")
+     ("wt" "Work Today"
+      ((tags-todo "DEADLINE=\"<+0d>\""
+                  ((org-agenda-overriding-header "Due today")
+                   (org-agenda-skip-function
+                    '(org-agenda-skip-entry-if 'notdeadline))
+                   (org-agenda-sorting-strategy '(priority-down))))
+       (tags-todo "DEADLINE<\"<+0d>\""
+                  ((org-agenda-overriding-header "Overdue")
+                   (org-agenda-skip-function
+                    '(org-agenda-skip-entry-if 'notdeadline))
+                   (org-agenda-sorting-strategy '(priority-down))))
+       (tags-todo "TODO={STARTED}"
+                  ((org-agenda-overriding-header "Started")
+                   (org-agenda-sorting-strategy '(priority-down))))
+       (tags "TODO={MEETING}+CREATED>\"<-7d>\""
+             ((org-agenda-overriding-header "Recent meetings (last 7 days)")))
+       (tags "TODO={NOTE}+CREATED>\"<-7d>\""
+             ((org-agenda-overriding-header "Recent notes (last 7 days)")))
+       (agenda ""
+               ((org-agenda-entry-types '(:scheduled))
+                (org-agenda-overriding-header "Scheduled")
+                (org-agenda-skip-function
+                 '(org-agenda-skip-entry-if 'todo 'done))
+                (org-agenda-sorting-strategy
+                 '(priority-down time-down))
+                (org-agenda-span 'day)
+                (org-agenda-start-on-weekday nil)
+                (org-agenda-time-grid nil))))
+      ((org-agenda-files `(,org-default-work-file))
+       (org-agenda-sorting-strategy '(deadline-up))))
+
+     ("wp" "For 1:1"
+      ((tags "people&TODO={TODO\\|STARTED}"
+             ((org-agenda-overriding-header "Tasks for 1:1")))))
+
+     ("p" . "Personal ...")
+     ("pt" "Personal Today"
+      ((tags-todo "DEADLINE=\"<+0d>\""
+                  ((org-agenda-overriding-header "Due today")
+                   (org-agenda-skip-function
+                    '(org-agenda-skip-entry-if 'notdeadline))
+                   (org-agenda-sorting-strategy '(priority-down))))
+       (tags-todo "DEADLINE<\"<+0d>\""
+                  ((org-agenda-overriding-header "Overdue")
+                   (org-agenda-skip-function
+                    '(org-agenda-skip-entry-if 'notdeadline))
+                   (org-agenda-sorting-strategy '(priority-down))))
+       (tags-todo "TODO={STARTED}"
+                  ((org-agenda-overriding-header "Started")
+                   (org-agenda-sorting-strategy '(priority-down))))
+       (tags "TODO={NOTE}+CREATED>\"<-7d>\""
+             ((org-agenda-overriding-header "Recent notes (last 7 days)")))
+       (agenda ""
+               ((org-agenda-entry-types '(:scheduled))
+                (org-agenda-overriding-header "Scheduled")
+                (org-agenda-skip-function
+                 '(org-agenda-skip-entry-if 'todo 'done))
+                (org-agenda-sorting-strategy
+                 '(priority-down time-down))
+                (org-agenda-span 'day)
+                (org-agenda-start-on-weekday nil)
+                (org-agenda-time-grid nil))))
+      ((org-agenda-files `(,org-default-personal-file
+                           ,org-default-notes-file))
+       (org-agenda-sorting-strategy '(deadline-up))))
+
+     ("r" . "Review ...")
+     ("rt" "Triage (unscheduled tasks)"
+      ((tags "TODO<>\"\"&TODO<>{DONE\\|CANCELED\\|NOTE\\|MEETING\\|PROJECT}"
+             ((org-agenda-overriding-header "Unscheduled tasks: ")
+              (org-agenda-skip-function
+               (quote
+                (org-agenda-skip-entry-if
+                 (quote scheduled)
+                 (quote deadline)
+                 (quote timestamp)
+                 (quote regexp)
+                 "\\* \\(SOMEDAY\\)")))
+              (org-agenda-sorting-strategy
+               (quote
+                (category-up)))
+              (org-agenda-prefix-format "%-11c%5(org-todo-age) ")))))
+
+     ("rs" "Someday tasks"
+      ((tags-todo "TODO={SOMEDAY}"
+                  ((org-agenda-overriding-header "NO DUE DATE / SOMEDAY")
+                   (org-agenda-skip-function
+                    '(org-agenda-skip-entry-if 'deadline))))))
+
+     ("h" "Hotlist (what's important and due soon)"
+      ((tags-todo "DEADLINE<\"<+0d>\""
+                  ((org-agenda-overriding-header "OVERDUE")))
+       (tags-todo "DEADLINE>=\"<+0d>\"+DEADLINE<=\"<+1w>\""
+                  ((org-agenda-overriding-header "DUE IN NEXT 7 DAYS")))
+       (tags-todo "DEADLINE=\"\"+PRIORITY={A}|DEADLINE>\"<+1w>\"+PRIORITY={A}"
+                  ((org-agenda-overriding-header "HIGH PRIORITY"))))
+      ((org-agenda-todo-ignore-scheduled 'future)
+       (org-agenda-sorting-strategy '(deadline-up)))))))
 
   ;; org babel related
   ;; prevent the conversion of spaces into tabs (necessary for Python code exports)
@@ -87,78 +207,58 @@
   (org-refile-use-outline-path 'file)
   (org-outline-path-complete-in-steps nil)
   (org-refile-allow-creating-parent-nodes 'confirm)
-  (org-refile-targets (append '((org-default-media-file :level . 1)
-                                (org-default-notes-file :level . 0))
-                              (->>
-                               (directory-files org-default-projects-dir nil ".org$")
-                               (-remove-item (file-name-base org-default-media-file))
-                               (--remove (s-starts-with? "." it))
-                               (--map (format "%s/%s" org-default-projects-dir it))
-                               (--map (cons it (cons :level 1))))))
+  (org-refile-targets (quote ((org-agenda-files :todo . "PROJECT")
+                              (org-default-notes-file :maxlevel . 1))))
+
+  (org-stuck-projects (quote ("TODO=\"PROJECT\"" ("TODO") nil "")))
+
+  (org-reverse-note-order t)
+
+  (org-todo-keyword-faces
+   (quote
+    (("TODO" :foreground "medium blue" :weight bold)
+     ("STARTED" :foreground "dark orange" :weight bold)
+     ("WAITING" :foreground "red" :weight bold)
+     ("DELEGATED" :foreground "dark violet" :weight bold)
+     ("NOTE" :foreground "purple" :weight bold)
+     ("PROJECT" :foreground "#088e8e" :weight bold)))
+     ("SOMEDAY" :foreground "dark blue" :weight bold)
+     ("MEETING" :foreground "deep sky blue" :weight bold))
 
   (org-capture-templates
-   `(("t" "task entry" entry
-      (file ,org-default-inbox-file )
-      "* %?\n:PROPERTIES:\n:CREATED: %U\n:END:\n%i")))
+   `(("t" "Add task" entry
+      (file ,org-default-inbox-file)
+      "* TODO %?\n:PROPERTIES:\n:ID: %(shell-command-to-string \"uuidgen\"):CREATED: %U\n:END:\n")
 
-  :config
-  (defhydra hydra-org-menu (:columns 6)
-     "
-  ^Navigate^      ^Refile^       ^Move^           ^Update^        ^Go To^        ^Dired^
-  ^^^^^^^^^^---------------------------------------------------------------------------------------
-  _k_: ↑ previous _t_: tasks     _m X_: projects  _T_: todo task  _g t_: tasks    _g X_: projects
-  _j_: ↓ next     _p_: personal  _m P_: personal  _S_: schedule   _g i_: incubate _g P_: personal
-  _c_: archive    _r_: refile    _m T_: technical _D_: deadline   _g n_: notes    _g T_: technical
-  _d_: delete     _i_: incubate                 _R_: rename     _g x_: inbox    _g C_: completed
-  "
-    ("<up>" org-previous-visible-heading)
-    ("<down>" org-next-visible-heading)
-    ("k" org-previous-visible-heading)
-    ("j" org-next-visible-heading)
-    ("c" fcuny/org-archive-subtree-as-completed)
-    ("d" org-cut-subtree)
-    ("t" fcuny/org-refile-to-task)
-    ("i" fcuny/org-refile-to-incubate)
-    ("p" fcuny/org-refile-to-personal-notes)
-    ("r" org-refile)
-    ("m X" fcuny/org-refile-to-projects-dir)
-    ("m P" fcuny/org-refile-to-personal-dir)
-    ("m T" fcuny/org-refile-to-technical-dir)
-    ("T" org-todo)
-    ("S" org-schedule)
-    ("D" org-deadline)
-    ("R" org-rename-header)
-    ("g t" (find-file-other-window org-default-tasks-file))
-    ("g i" (find-file-other-window org-default-incubate-file))
-    ("g x" (find-file-other-window org-default-inbox-file))
-    ("g c" (find-file-other-window org-default-completed-file))
-    ("g n" (find-file-other-window org-default-notes-file))
-    ("g X" (dired org-default-projects-dir))
-    ("g P" (dired org-default-personal-dir))
-    ("g T" (dired org-default-technical-dir))
-    ("g C" (dired org-default-completed-dir))
-    ("[\t]" (org-cycle))
-    ("s" (org-save-all-org-buffers) "save")
-    ("q" nil "quit"))
-
-  :init
-  (defun fcuny/org-mode-setup ()
-    (let* ((base-font-color     (face-foreground 'default nil 'default))
-            (headline `(:inherit default :weight bold :foreground ,base-font-color)))
-      (custom-theme-set-faces 'user `(org-document-title ((t (,@headline :height 1.5)))))
-      (custom-theme-set-faces 'user `(org-level-1 ((t (,@headline :height 1.3)))))
-      (custom-theme-set-faces 'user `(org-level-2 ((t (:height 1.1))))))))
+     ("m" "Meeting" entry
+      (file ,org-default-inbox-file)
+      "* MEETING %u %?\n:PROPERTIES:\n:ID: %(shell-command-to-string \"uuidgen\"):CREATED: %U\n:END:\n")
+
+     ("n" "Note" entry
+      (file ,org-default-inbox-file)
+      "* NOTE %?\n:PROPERTIES:\n:ID: %(shell-command-to-string \"uuidgen\"):CREATED: %U\n:END:\n")
+
+     ("j" "Journal" entry
+      (file+olp+datetree ,org-default-journal-file)
+      "* %?" :tree-type month))))
 
 (use-package htmlize
   :ensure t)
 
-(use-package org-journal
-  :ensure t
-  :after (org)
-  :custom
-  (org-journal-file-format "%Y-%m.org")
-  (org-journal-dir "~/Documents/notebooks/journal/")
-  (org-journal-date-format 'fcuny/org-journal-date-format-func)
-  (org-journal-file-type `monthly))
+(defun fcuny/org-todo-age-time (&optional pos)
+  (let ((stamp (org-entry-get (or pos (point)) "CREATED" t)))
+    (when stamp
+      (time-subtract (current-time)
+                     (org-time-string-to-time
+                      (org-entry-get (or pos (point)) "CREATED" t))))))
+
+(defun fcuny/org-todo-age (&optional pos)
+  (let ((days (time-to-number-of-days (fcuny/org-todo-age-time pos))))
+    (cond
+     ((< days 1)   "today")
+     ((< days 7)   (format "%dd" days))
+     ((< days 30)  (format "%.1fw" (/ days 7.0)))
+     ((< days 358) (format "%.1fM" (/ days 30.0)))
+     (t            (format "%.1fY" (/ days 365.0))))))
 
 (provide 'fcuny-org)