conf-org.el 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856
  1. ;;; Code:
  2. (require 'alert)
  3. (require 'org)
  4. (require 'appt)
  5. (require 'org-clock)
  6. (require 'org-habit)
  7. (require 'org-goto)
  8. (require 'org-depend)
  9. (require 'org-contacts)
  10. (require 'org-notify)
  11. (require 'org-mime nil 'noerror)
  12. (require 'org-crypt)
  13. (require 'org-protocol)
  14. (require 'org-projectile)
  15. (require 'org-annotate-file)
  16. (require 'gnus-icalendar)
  17. (require 'midnight)
  18. (require 'bookmark)
  19. (with-eval-after-load 'ox
  20. (require 'ox-rst)
  21. (require 'ox-hugo))
  22. ;; Vars
  23. (defvar-local distopico:org--directory (expand-file-name "~/Documents/org/"))
  24. (defvar-local distopico:org--agenda-files '("daily.org" "calendar.org" "notes.org" "life.org" "todo.org" "contacts.org"))
  25. (defvar-local distopico:org--special-categories '("Holiday" "Birthday" "Vacation"))
  26. (defvar-local distopico:org--icons (in-emacs-d "themes/icons/"))
  27. (defvar-local distopico:org--clock-default-effort "1:00")
  28. (defvar-local distopico::org--state-remove-trigger '("TODO" "HOLD"))
  29. (defvar distopico:org--appt-current nil)
  30. ;; Configuration
  31. (setq org-modules
  32. (append org-modules
  33. '(org-contacts
  34. org-habit
  35. org-toc
  36. org-notify
  37. ol-gnus
  38. ;;org-pomodoro
  39. org-depend
  40. org-mime
  41. org-crypt
  42. org-protocol
  43. org-projectile)))
  44. ;; General settings
  45. (setq org-directory distopico:org--directory
  46. org-startup-folded t
  47. org-log-done 'time
  48. org-log-into-drawer t
  49. org-auto-align-tags t
  50. org-support-shift-select t
  51. org-track-ordered-property-with-tag t
  52. org-src-fontify-natively t
  53. org-src-tab-acts-natively t
  54. org-yank-adjusted-subtrees t
  55. org-use-speed-commands t
  56. org-special-ctrl-k t
  57. org-special-ctrl-a/e t
  58. ;; org-startup-indented nil
  59. ;; org-hide-leading-stars nil
  60. org-src-preserve-indentation t
  61. org-reverse-note-order nil
  62. org-M-RET-may-split-line nil
  63. org-cycle-separator-lines 2
  64. org-blank-before-new-entry '((heading . auto) (plain-list-item . auto)) ;; TODO: check this if have problems with blank spaces
  65. org-tags-column -120
  66. org-refile-use-outline-path nil
  67. org-refile-allow-creating-parent-nodes 'confirm
  68. org-refile-targets '((org-agenda-files . (:maxlevel . 4)))
  69. org-goto-interface 'outline
  70. org-goto-max-level 10)
  71. ;; Contacts
  72. (setq org-contacts-files (list (expand-file-name "contacts.org" org-directory)))
  73. ;; Diary to Org
  74. (setq diary-file (concat org-directory "diary")
  75. org-agenda-diary-file (expand-file-name "calendar.org" org-directory))
  76. ;;Archive
  77. (setq org-archive-location (expand-file-name "archive/archive_%s::" org-directory))
  78. ;; General Notes
  79. (setq org-default-notes-file (expand-file-name "notes.org" org-directory))
  80. ;; Annotation
  81. (setq org-annotate-file-storage-file (expand-file-name "notes.org" org-directory)
  82. org-annotate-file-add-search t)
  83. ;; Workflow definition
  84. (setq org-use-fast-todo-selection t
  85. org-enforce-todo-dependencies t
  86. org-todo-keywords
  87. '((sequence "TODO(t)" "NEXT(n)" "STARTED(s!)" "|" "DONE(d!)")
  88. (sequence "HOLD(h)" "WAITING(w@/!)" "|" "CANCELED(c@/!)")
  89. (sequence "PROJECT(p!)" "|" "SOMEDAY(m)"))
  90. org-stuck-projects
  91. '("TODO=\"HOLD\"|TODO=\"PROJECT\"|@distopia/-DONE"
  92. ("TODO" "NEXT" "STARTED" "WAITING")
  93. nil "")
  94. org-todo-state-tags-triggers '(("CANCELLED" ("archive" . t)))
  95. org-clock-out-when-done '("HOLD" "WAITING" "CANCELLED" "DONE")
  96. org-todo-keyword-faces
  97. '(("TODO" . (:foreground "#df3800" :weight bold))
  98. ("STARTED" . (:foreground "#e0c625" :weight bold))
  99. ("NEXT" . (:foreground "DeepPink2" :weight bold))
  100. ("HOLD" . (:foreground "#b68800" :weight bold))
  101. ("WAITING" . (:foreground "#4d9694" :weight bold))
  102. ("CANCELED" . (:foreground "#566ea2" :weight bold))
  103. ("DONE" . (:foreground "#448c27" :weight bold))
  104. ("PROJECT" . (:foreground "orchid" :weight bold)))
  105. org-default-priority ?D
  106. org-lowest-priority ?E
  107. org-priority-faces
  108. '((?A . "#f01a0f")
  109. (?B . "#f0640f")
  110. (?C . "light sea green")
  111. (?D . "slate blue")))
  112. ;; Default tags
  113. (setq org-tag-persistent-alist
  114. '(("@work" . ?b)
  115. ("@home" . ?h)
  116. ("@bookmarks" . ?m)
  117. ("@writing" . ?w)
  118. ("@errands" . ?e)
  119. ("@haking" . ?c)
  120. ("@reading" . ?r)
  121. ("@laptop" . ?l)
  122. ("@pc" . ?p)
  123. ("@weekly" . ?W)
  124. ("@family" . ?f)))
  125. ;; Templates
  126. (setq org-capture-templates
  127. `(;; General todo task
  128. ("t" "Todo" entry
  129. (file+headline ,(concat org-directory "todo.org") "Backlog")
  130. "* TODO %?\n%A\n%i\n" :prepend t :clock-resume t :refile-targets ((nil :maxlevel . 1)))
  131. ;; Task with specific time
  132. ("T" "Tasks" entry
  133. (file+headline ,(concat org-directory "todo.org") "Various Tasks")
  134. "* TODO %^{Task}%?\n SCHEDULED: %^t\n")
  135. ;; Task with minimum effort
  136. ("q" "Quick task" item
  137. (file+headline ,(concat org-directory "todo.org") "Quick Task")
  138. "- [ ] %^{Task}" :immediate-finish t)
  139. ;; Web bookmark
  140. ("B" "Bookmark" item
  141. (file+function ,(concat org-directory "bookmarks.org") distopico:org-ask-headline-target)
  142. "- %a \n%?%:initial\n\n" :refile-targets ((nil :maxlevel . 2)))
  143. ;; Notes to remember with custom title
  144. ("n" "Note" entry
  145. (file+headline org-default-notes-file "General Notes")
  146. "* %^{Title}\n :PROPERTIES:\n:CREATED:%U\n:END:\n\n%i\n\n%a"
  147. :prepend t :empty-lines 1)
  148. ;; Note to remember without tittle
  149. ("Q" "Quick note" item
  150. (file+headline org-default-notes-file "Quick Notes"))
  151. ;; Some unexpected idea about a project
  152. ("i" "Idea" entry
  153. (file+headline org-default-notes-file "Idea")
  154. "* %^{Title}\n %i" :prepend t)
  155. ;; Manage contacts list
  156. ("c" "Contacts" entry
  157. (file+headline distopico:contacts-files "General")
  158. "* %(org-contacts-template-name)%?\n:PROPERTIES:\n:EMAIL: %(org-contacts-template-email)\n:NICKNAME: \n:END:\n"
  159. :refile-targets ((nil :maxlevel . 1)))
  160. ;; Organized my habits of day
  161. ("h" "Habit" entry
  162. (file+headline ,(concat org-directory "daily.org") "Habits")
  163. "* TODO %?\nSCHEDULED: %(format-time-string \"<%Y-%m-%d %h %H:%M .+1d/3d>\")\n:PROPERTIES:\n:STYLE: habit\n:REPEAT_TO_STATE: NEXT\n:CAPTURED: %U\n:END:"
  164. :clock-resume t)
  165. ;; Some real life tasks
  166. ("l" "Life Task" entry
  167. (file+headline ,(concat org-directory "life.org") "Life Tasks")
  168. "* TODO %?\n %i\n%a")
  169. ;; For my life
  170. ("b" "Stuff to buy" entry
  171. (file+headline ,(concat org-directory "life.org") "Stuff to buy")
  172. "* TODO %^{Title}%?\n" :prepend t)
  173. ;; Notes without specific space
  174. ("o" "Organizer" entry
  175. (file+function org-default-notes-file distopico:org-ask-headline-target)
  176. "** %?\n<%<%Y-%m-%d %a %T>>")
  177. ;; I haven't many events in my life
  178. ("e" "Event" entry
  179. (file+headline ,(concat org-directory "calendar.org") "Events")
  180. "* %^{Event}%? %^g\n%i\n%^T\n:PROPERTIES:\n:APPT_WARNTIME: %^{Wartime min/hour}\n:END:\n")
  181. ;; Some event in website
  182. ("E" "Event Link" entry
  183. (file+headline ,(concat org-directory "calendar.org") "Events")
  184. "* %^{Event}%? %^g\n%A\n%^T\n%i\n:PROPERTIES:\n:APPT_WARNTIME: %^{Wartime min/hour}\n:END:\n")
  185. ;; Remember response some email
  186. ("M" "Messages" entry
  187. (file+headline org-default-notes-file "Messages")
  188. "* NEXT Respond to %:fromaddress on %:subject\nSCHEDULED: %t\n CAPTURED: %U\n%a\n")))
  189. ;; Agenda
  190. (setq org-agenda-files (mapcar (lambda (x) (expand-file-name x org-directory)) distopico:org--agenda-files)
  191. org-agenda-window-setup 'only-window
  192. org-agenda-restore-windows-after-quit t
  193. org-agenda-skip-deadline-prewarning-if-scheduled t
  194. org-agenda-skip-timestamp-if-done t
  195. org-agenda-skip-deadline-if-done t
  196. org-agenda-skip-scheduled-if-done t
  197. org-agenda-insert-diary-extract-time t
  198. org-agenda-todo-list-sublevels t
  199. org-agenda-dim-blocked-tasks t
  200. ;; nil
  201. org-agenda-include-diary nil
  202. org-agenda-sticky nil
  203. org-agenda-remove-tags nil
  204. ;; Other
  205. org-agenda-tags-column -102
  206. org-agenda-span 2
  207. org-agenda-day-face-function 'distopico:org-agenda-day-face-special-function
  208. org-agenda-category-icon-alist
  209. `(("Emacs"
  210. ,(if window-system
  211. "~/.emacs.d/themes/icons/emacs.png"
  212. (list "ξ")) nil nil :ascent center)
  213. ("Holiday\\|Vacation"
  214. ,(if window-system
  215. "~/.emacs.d/themes/icons/holidays.png"
  216. (list "☀")) nil nil :ascent center)
  217. (".*" '(space . (:width (16)))))
  218. org-agenda-custom-commands
  219. '(("p" "Projects" tags "@distopia|PROJECT"
  220. ((org-agenda-dim-blocked-tasks t)
  221. (org-agenda-skip-scheduled-if-done nil)
  222. (org-agenda-skip-deadline-if-done nil)
  223. (org-agenda-todo-ignore-with-date nil)
  224. (org-agenda-todo-ignore-scheduled nil)
  225. (org-agenda-todo-ignore-deadlines nil)))
  226. ("N" "Next to do" tags-todo "next|NEXT|SCHEDULED=\".*\"")
  227. ("b" "Things to buy any time" tags-todo "+tobuy+SCHEDULED=\"\"")
  228. ("y" "Syadmin stuff to do" tags-todo "+sysadmin+SCHEDULED=\"\"")
  229. ("D" "Daily tasks:" tags "daily|CATEGORY=\"daily\"|STYLE=\"habit\"")))
  230. ;;Appointment
  231. (setq appt-audible nil
  232. appt-display-diary nil
  233. appt-display-mode-line t
  234. appt-display-format 'window
  235. appt-message-warning-time 16
  236. appt-display-interval 8
  237. appt-disp-window-function 'distopico:org-appt-disp-window-function
  238. appt-delete-window-function 'distopico:org-appt-delete-window-function)
  239. ;; Notify
  240. (setq org-notify-audible nil)
  241. (org-notify-add 'default
  242. '(:time "16m" :duration 20 :actions -notify)
  243. '(:time "2h" :actions -message)
  244. '(:time "3d" :actions -email))
  245. ;; Clocks
  246. (setq org-clock-auto-clock-resolution 'when-no-clock-is-running
  247. org-clock-clocktable-default-properties '(:maxlevel 3 :scope file)
  248. org-clock-history-length 20
  249. org-clock-in-resume t
  250. org-clock-in-switch-to-state 'distopico:clock-in-to-next
  251. org-clock-out-remove-zero-time-clocks t
  252. org-clock-into-drawer t
  253. org-clock-persist 'history
  254. org-clock-report-include-clocking-task t
  255. org-show-notification-handler 'distopico:show-notification-handler
  256. org-clock-persist-file (in-emacs-d ".cache/org-clock-save.el"))
  257. ;; Habits
  258. (setq org-habit-graph-column 60
  259. org-habit-show-done-always-green t)
  260. ;; mu4e
  261. (setq org-capture-templates-contexts
  262. '(("M" ((in-mode . "mu4e-headers-mode")
  263. (in-mode . "mu4e-view-mode")))))
  264. (setq gnus-icalendar-org-capture-file (concat org-directory "calendar.org")
  265. gnus-icalendar-org-capture-headline '("Personal"))
  266. ;; Org Projectile
  267. (setq org-projectile-projects-file (expand-file-name "todo.org" org-directory))
  268. (push (org-projectile-project-todo-entry) org-capture-templates)
  269. ;; (add-to-list 'org-capture-templates
  270. ;; (org-projectile:project-todo-entry "p" "* TODO %? %a" "Project Todo"))
  271. ;; Add export back-ends
  272. (dolist (source '(md gfm rst))
  273. (add-to-list 'org-export-backends source t))
  274. ;; Babel
  275. (org-babel-do-load-languages
  276. 'org-babel-load-languages
  277. '((emacs-lisp . t)
  278. (js . t)
  279. (css . t)
  280. (latex . t)
  281. (python . t)
  282. (shell . t)))
  283. ;; Crypt
  284. (org-crypt-use-before-save-magic)
  285. (setq org-tags-exclude-from-inheritance '("crypt")
  286. org-crypt-disable-auto-save t)
  287. ;; midnight
  288. (setq midnight-mode t)
  289. (remove-hook 'midnight-hook 'clean-buffer-list)
  290. ;; Custom map key
  291. (define-key org-mode-map (kbd "C-M-s-<return>") 'distopico:org-insert-todo-subheading)
  292. (define-key org-mode-map (kbd "C-M-<return>") 'distopico:org-insert-subheading)
  293. (define-key org-mode-map (kbd "M-s-<return>") 'distopico:org-insert-heading-for-next-day)
  294. (define-key org-mode-map (kbd "C-c k") 'org-cut-subtree)
  295. (define-key org-mode-map (kbd "C-c q") 'org-copy-subtree)
  296. (define-key org-mode-map (kbd "C-c y") 'org-paste-subtree)
  297. (define-key org-agenda-mode-map (kbd "C-<tab>") 'org-agenda-cycle-show)
  298. (define-key org-agenda-mode-map (kbd "M-d") 'distopico:org-agenda-done)
  299. (define-key org-agenda-mode-map (kbd "M-D") 'distopico:org-agenda-mark-done-and-add)
  300. (define-key org-agenda-mode-map (kbd "M-n") 'distopico:org-agenda-new)
  301. (define-key org-agenda-mode-map (kbd "M-y") 'org-agenda-todo-yesterday)
  302. (define-key org-agenda-mode-map (kbd "M-p") 'org-pomodoro)
  303. (define-key org-agenda-mode-map (kbd "M-q") 'org-agenda-quit)
  304. (define-key org-agenda-mode-map (kbd "C-q") 'bury-buffer)
  305. (define-key org-agenda-mode-map "q" 'bury-buffer)
  306. (define-key bookmark-bmenu-mode-map (kbd "a") 'distopico:org-show-annotations-bookmark)
  307. (add-to-list 'org-speed-commands '("n" distopico:org-show-next-heading-tidily))
  308. (add-to-list 'org-speed-commands '("p" distopico:org-show-previous-heading-tidily))
  309. ;; Update always at 9:30
  310. (run-at-time "9:30" nil 'distopico:org-show-agenda-appt)
  311. ;; Update org-agenda buffer each 10min/600sec
  312. (run-at-time nil 600 'distopico:org-agenda-redo-in-other-window)
  313. ;; Functions
  314. (with-no-warnings (defvar date))
  315. (defun distopico:org-lunar-phases ()
  316. "Show lunar phase in Agenda buffer."
  317. (let* ((phase-list (lunar-phase-list (nth 0 date) (nth 2 date)))
  318. (phase (cl-find-if (lambda (phase) (equal (car phase) date))
  319. phase-list)))
  320. (when phase
  321. (setq ret (concat (lunar-phase-name (nth 2 phase)) " "
  322. (substring (nth 1 phase) 0 5))))))
  323. (defun distopico:show-notification-handler (message)
  324. "Handler for `org-mode' notifications using `alert' mode.
  325. Display the `MESSAGE' as body notification.
  326. TODO: make this generic to replace `distopico:org-appt-disp-window-function'."
  327. (progn
  328. (alert message
  329. :title "Org-mode"
  330. :mode 'org-mode
  331. :severity 'normal
  332. :style 'notifications
  333. :category 'emacs
  334. :icon (concat distopico:org--icons "org-mode.png"))))
  335. (defun distopico:org-appt-disp-window-function (left time message)
  336. "Show notification on appointments based on `LEFT' `TIME' `MESSAGE'."
  337. (progn
  338. (add-to-list 'distopico:org--appt-current message)
  339. (alert message
  340. :title (concat "Appointment "
  341. (cond ((equal left "0") "now!")
  342. ((equal left "1") "in 1 minute!")
  343. (t (format "in %s minutes" left))))
  344. :mode 'org-mode
  345. :severity 'moderate
  346. :style 'notifications
  347. :category 'emacs
  348. :icon (concat distopico:org--icons "org-mode.png"))))
  349. (defun distopico:org-appt-delete-window-function ()
  350. "Delete appointment after show it."
  351. (if distopico:org--appt-current
  352. (setq distopico:org--appt-current
  353. (delete (nth 0 distopico:org--appt-current) distopico:org--appt-current))))
  354. (defun distopico:org-remove-redundant-tags ()
  355. "Remove redundant tags of headlines in current buffer.
  356. A tag is considered redundant if it is local to a headline and
  357. inherited by a parent headline.
  358. From https://github.com/thisirs/dotemacs/blob/master/init-org.el"
  359. (interactive)
  360. (when (eq major-mode 'org-mode)
  361. (save-excursion
  362. (org-map-entries
  363. (lambda ()
  364. (let ((alltags (split-string (or (org-entry-get (point) "ALLTAGS") "") ":"))
  365. local inherited tag)
  366. (dolist (tag alltags)
  367. (if (get-text-property 0 'inherited tag)
  368. (push tag inherited) (push tag local)))
  369. (dolist (tag local)
  370. (if (member tag inherited) (org-toggle-tag tag 'off)))))
  371. t nil))))
  372. (defun distopico:org-saveplace ()
  373. "Fix a problem with saveplace.el putting you back in a folded position."
  374. (when (outline-invisible-p)
  375. (save-excursion
  376. (outline-previous-visible-heading 1)
  377. (org-show-subtree))))
  378. (defun distopico:org-show-next-heading-tidily ()
  379. "Show next entry, keeping other entries closed."
  380. (if (save-excursion (end-of-line) (outline-invisible-p))
  381. (progn (org-show-entry) (show-children))
  382. (outline-next-heading)
  383. (unless (and (bolp) (org-on-heading-p))
  384. (org-up-heading-safe)
  385. (outline-hide-subtree)
  386. (org-cycle-show-empty-lines t)
  387. (message "Boundary reached"))
  388. (org-overview)
  389. (org-cycle-show-empty-lines t)
  390. (org-reveal t)
  391. (org-show-entry)
  392. (outline-show-children)
  393. (org-cycle-show-empty-lines t) ))
  394. (defun distopico:org-show-previous-heading-tidily ()
  395. "Show previous entry, keeping other entries closed."
  396. (let ((pos (point)))
  397. (outline-previous-heading)
  398. (unless (and (< (point) pos) (bolp) (org-on-heading-p))
  399. (goto-char pos)
  400. (outline-hide-subtree)
  401. (org-cycle-show-empty-lines t)
  402. (message "Boundary reached"))
  403. (org-overview)
  404. (org-cycle-show-empty-lines t)
  405. (org-reveal t)
  406. (org-show-entry)
  407. (outline-show-children)
  408. (org-cycle-show-empty-lines t) ))
  409. (defun distopico:org-insert-subheading (arg)
  410. "Insert a new subheading `ARG' and demote it same to `org-insert-subheading'.
  411. This also removes blank lines from level 1.
  412. Works for outline headings and for plain lists alike."
  413. (interactive "P")
  414. (org-insert-heading-respect-content arg)
  415. (let ((pos (point)))
  416. (let ((cur-level (org-current-level))
  417. (prev-level (org-get-previous-line-level)))
  418. (when (= prev-level 1)
  419. (forward-line -1)
  420. (delete-blank-lines)
  421. (goto-char (min (point) pos)))))
  422. (cond
  423. ((org-at-heading-p) (org-do-demote))
  424. ((org-at-item-p) (org-indent-item)))
  425. (end-of-line))
  426. (defun distopico:org-insert-todo-subheading (arg)
  427. "Insert a new subheading `ARG' with TODO keyword or checkbox and demote it.
  428. Same to `org-insert-subheading' but remove blank lines from level 1.
  429. Works for outline headings and for plain lists alike."
  430. (interactive "P")
  431. (org-insert-todo-heading-respect-content arg)
  432. (let ((pos (point)))
  433. (let ((cur-level (org-current-level))
  434. (prev-level (org-get-previous-line-level)))
  435. (when (= prev-level 1)
  436. (forward-line -1)
  437. (delete-blank-lines)
  438. (goto-char (min (point) pos)))))
  439. (cond
  440. ((org-at-heading-p) (org-do-demote))
  441. ((org-at-item-p) (org-indent-item)))
  442. (end-of-line))
  443. (defun distopico:org-insert-heading-for-next-day ()
  444. "Insert a same-level heading for the following day.
  445. from: http://pages.sachachua.com/.emacs.d/Sacha.html"
  446. (interactive)
  447. (let ((new-date
  448. (seconds-to-time
  449. (+ 86400.0
  450. (float-time
  451. (org-read-date nil 'to-time (elt (org-heading-components) 4)))))))
  452. (org-insert-heading-after-current)
  453. (insert (format-time-string "%Y-%m-%d\n" new-date))))
  454. (defun distopico:org-insert-trigger ()
  455. "Automatically insert chain-find-next trigger on NEXT state."
  456. (cond ((equal org-state "NEXT")
  457. (unless org-depend-doing-chain-find-next
  458. (org-set-property "TRIGGER" "chain-find-next(NEXT,from-current,priority-up,effort-down)")))
  459. ((member org-state distopico::org--state-remove-trigger)
  460. (save-excursion
  461. (org-show-entry)
  462. (org-delete-property "TRIGGER")))))
  463. (defun distopico:org-toggle-next-tag ()
  464. "Org possibly toggle next tag based on todo keyword."
  465. (save-excursion
  466. (org-back-to-heading)
  467. (let ((todo-is-next (equal (org-get-todo-state) "NEXT"))
  468. (next-in-tags (member "NEXT" (org-get-tags))))
  469. (if (or (and todo-is-next (not next-in-tags))
  470. (and (not todo-is-next) next-in-tags))
  471. (org-toggle-tag "next" 'on)
  472. (org-toggle-tag "next" 'off)))))
  473. (defun distopico:org:remove-empty-propert-drawers ()
  474. "Remove all empty property drawers in current file."
  475. (interactive)
  476. (unless (eq major-mode 'org-mode)
  477. (error "You need to turn on Org mode for this function"))
  478. (save-excursion
  479. (goto-char (point-min))
  480. (while (re-search-forward ":PROPERTIES:" nil t)
  481. (save-excursion
  482. (org-remove-empty-drawer-at (match-beginning 0))))))
  483. (defun distopico:org-add-default-effort ()
  484. "Add a default effort estimation."
  485. (unless (org-entry-get (point) "Effort")
  486. (org-set-property "Effort" distopico:org--clock-default-effort)))
  487. (defun distopico:org-agenda-redo-in-other-window ()
  488. "Call `org-agenda-redo' function even in the non-agenda buffer."
  489. (interactive)
  490. (let ((agenda-window (get-buffer-window org-agenda-buffer-name t)))
  491. (when agenda-window
  492. (with-selected-window agenda-window (org-agenda-redo)))))
  493. (defun distopico:org-show-agenda (&optional open-same-window)
  494. "Switch to the org agenda, or prompt for new one if one does not exist.
  495. optional `OPEN-SAME-WINDOW'"
  496. (interactive "P")
  497. (let ((agenda-buffer (get-buffer "*Org Agenda*")))
  498. (if agenda-buffer
  499. (if open-same-window
  500. (switch-to-buffer agenda-buffer)
  501. (switch-to-buffer-other-window agenda-buffer))
  502. (org-agenda-list))
  503. (tabbar-local-mode 1)))
  504. (defun distopico:org-show-agenda-appt ()
  505. "Update appt and show agenda."
  506. (interactive)
  507. (distopico:org-show-agenda))
  508. (defun distopico:org-agenda-done (&optional arg)
  509. "Mark current TODO as done optional `ARG' are unused.
  510. This change the line at point, all other lines in the agenda
  511. referring to the same tree node, and the headline of the
  512. tree node in the Org-mode file.
  513. from: http://pages.sachachua.com/.emacs.d/Sacha.html"
  514. (interactive "P")
  515. (org-agenda-todo "DONE"))
  516. (defun distopico:org-agenda-mark-done-and-add ()
  517. "Mark the current TODO as done and add another task after it.
  518. Creates it at the same level as the previous task, so it's better to use
  519. this with to-do items than with projects or headings.
  520. from: http://pages.sachachua.com/.emacs.d/Sacha.html"
  521. (interactive)
  522. (org-agenda-todo "DONE")
  523. (org-agenda-switch-to)
  524. (org-capture 0 "t"))
  525. (defun distopico:org-agenda-new ()
  526. "Create a new note or task at the current agenda item.
  527. Creates it at the same level as the previous task, so it's better to use
  528. this with to-do items than with projects or headings."
  529. (interactive)
  530. (org-agenda-switch-to)
  531. (org-capture 0))
  532. (defun distopico:org-agenda-day-face-special-function (date)
  533. "Compute DATE face for holidays/vacations/birthday."
  534. (unless (org-agenda-today-p date)
  535. (dolist (file (org-agenda-files nil 'ifmode))
  536. (let ((face
  537. (dolist (entry (org-agenda-get-day-entries file date))
  538. (let ((category (with-temp-buffer
  539. (insert entry)
  540. (org-get-category (point-min)))))
  541. (when (string-match
  542. (mapconcat 'downcase distopico:org--special-categories "\\|")
  543. category)
  544. (cl-return '(:foreground "PaleGreen")))))))
  545. (when face (cl-return face))))))
  546. (defun distopico:org-update-agenda-views ()
  547. "Update all org agenda buffers (if any)."
  548. (save-window-excursion
  549. (mapc
  550. (lambda (buf)
  551. (with-current-buffer buf
  552. (org-agenda-redo t)))
  553. (get-buffers-with-major-mode 'org-agenda-mode))))
  554. (defun distopico:remove-empty-drawer-on-clock-out ()
  555. "Delete clocking drawer if it is empty."
  556. (save-excursion
  557. (goto-char (point-min))
  558. (while (re-search-forward ":LOGBOOK:" nil t) ;
  559. (save-excursion
  560. (org-remove-empty-drawer-at (match-beginning 0))))
  561. (while (re-search-forward ":CLOCK:" nil t) ;
  562. (save-excursion
  563. (org-remove-empty-drawer-at (match-beginning 0))))))
  564. (defun distopico:clock-in-to-next (state) ;
  565. "Switch task from TODO `STATE' to NEXT when clocking in.
  566. Skips capture tasks and tasks with subtasks."
  567. (if (and (string-equal state "TODO")
  568. (not (or (string-equal "*Remember*" (buffer-name))
  569. (string-prefix-p "CAPTURE-" (buffer-name)))))
  570. (let ((subtree-end (save-excursion (org-end-of-subtree t)))
  571. (has-subtask nil))
  572. (save-excursion
  573. (forward-line 1)
  574. (while (and (not has-subtask)
  575. (< (point) subtree-end)
  576. (re-search-forward "^\*+ " subtree-end t))
  577. (when (member (org-get-todo-state) org-not-done-keywords)
  578. (setq has-subtask t))))
  579. (when (not has-subtask)
  580. "NEXT"))))
  581. (defun distopico:org-clock-in-set-state-to-started ()
  582. "Mark STARTED when clocked in."
  583. (save-excursion
  584. (catch 'exit
  585. (cond
  586. ((derived-mode-p 'org-agenda-mode)
  587. (let* ((marker (or (org-get-at-bol 'org-marker)
  588. (org-agenda-error)))
  589. (hdmarker (or (org-get-at-bol 'org-hd-marker) marker))
  590. (pos (marker-position marker))
  591. (col (current-column))
  592. newhead)
  593. (org-with-remote-undo (marker-buffer marker)
  594. (with-current-buffer (marker-buffer marker)
  595. (widen)
  596. (goto-char pos)
  597. (org-back-to-heading t)
  598. (if (org-get-todo-state)
  599. (org-todo "STARTED"))))))
  600. (t (if (org-get-todo-state)
  601. (org-todo "STARTED")))))))
  602. (defun distopico:org-inherited-no-file-tags ()
  603. "Preserves the logic of level one groupings."
  604. (let ((tags (org-entry-get nil "ALLTAGS" 'selective))
  605. (ltags (org-entry-get nil "TAGS")))
  606. (mapc (lambda (tag)
  607. (setq tags
  608. (replace-regexp-in-string (concat tag ":") "" tags)))
  609. (append org-file-tags (when ltags (split-string ltags ":" t))))
  610. (if (string= ":" tags) nil tags)))
  611. (defun distopico:org-ask-headline-target (&optional prompt targets)
  612. "Ask headline location, optional pass custom `PROMPT' text and `TARGETS'."
  613. (let* ((loc-prompt (or prompt "Headline"))
  614. (org-refile-targets (or targets '((nil :maxlevel . 2))))
  615. (hd (condition-case nil
  616. (car (org-refile-get-location loc-prompt nil t))
  617. (error (car org-refile-history)))))
  618. (goto-char (point-min))
  619. (outline-next-heading)
  620. (if (re-search-forward
  621. (format org-complex-heading-regexp-format (regexp-quote hd))
  622. nil t)
  623. (goto-char (point-at-bol))
  624. (goto-char (point-max)))))
  625. (defun distopico:org-show-annotations-bookmark ()
  626. "Opens the annotations window for the currently selected bookmark file."
  627. (interactive)
  628. (bookmark-bmenu-other-window)
  629. (org-annotate-file))
  630. (defun distopico:org-run-appt ()
  631. "Run org appointments."
  632. (interactive)
  633. (setq appt-time-msg-list nil)
  634. (when (not appt-timer)
  635. (appt-activate +1))
  636. (org-agenda-to-appt))
  637. (defun distopico:org-appt-add-hook-async ()
  638. (async-start
  639. `(lambda ()
  640. (require 'org-agenda)
  641. ,(add-hook 'after-init-hook
  642. `(lambda ()
  643. ,(distopico:org-run-appt)
  644. ))) 'ignore))
  645. (defun distopico:org-reset-appts ()
  646. "This also reverts all files, but it does update the appt list."
  647. (interactive)
  648. (setq appt-time-msg-list nil)
  649. (cl-flet ((yes-or-no-p (x) t))
  650. (org-revert-all-org-buffers))
  651. (org-agenda-to-appt))
  652. ;; Advice functions
  653. (defun distopico:org--capture-refile (orig-fun &rest args)
  654. "Advise or `org--capture-refile' to use `prepend' property.
  655. This wrap `ORIG-FUN' with it `ARGS' overwriting `org-reverse-note-order'."
  656. (let ((org-reverse-note-order (org-capture-get :prepend 'local)))
  657. (apply orig-fun args)))
  658. (defun distopico:org--capture-finalize (&optional stay-with-capture)
  659. "Advise capture-finalize to close the frame.
  660. See: `org-capture-finalize' for `STAY-WITH-CAPTURE' docs."
  661. (if (equal "emacs-capture" (frame-parameter nil 'name))
  662. (delete-frame)))
  663. (defun distopico:org--capture-kill ()
  664. "Advise capture-kill to close the frame."
  665. (if (equal "emacs-capture" (frame-parameter nil 'name))
  666. (delete-frame)))
  667. (defadvice org-archive-subtree (around distopico:org-archive-subtree-low-level activate)
  668. "Preserve top level headings when archiving to a file."
  669. ;; TODO: migrate to new advice
  670. (let ((tags (distopico:org-inherited-no-file-tags))
  671. (afile (car (org-archive--compute-location
  672. (or (org-entry-get nil "ARCHIVE" 'inherit) org-archive-location))))
  673. (org-archive-location
  674. (if (save-excursion (org-back-to-heading)
  675. (> (org-outline-level) 1))
  676. (concat (car (split-string org-archive-location "::"))
  677. "::* "
  678. (car (org-get-outline-path)))
  679. org-archive-location)))
  680. ad-do-it
  681. (when (and (not current-prefix-arg)
  682. (not (use-region-p)))
  683. (with-current-buffer (find-file-noselect afile)
  684. (save-excursion
  685. (while (org-up-heading-safe))
  686. (org-set-tags-to tags))))))
  687. (advice-add #'org-capture-refile :around 'distopico:org--capture-refile)
  688. (advice-add #'org-capture-finalize :after 'distopico:org--capture-finalize)
  689. (advice-add #'org-capture-kill :after 'distopico:org--capture-kill)
  690. ;; Hooks
  691. (defun distopico:org-init-hook ()
  692. "Hook for set up `org-mode' on init."
  693. ;; Org mime messages to HTML
  694. (when (fboundp 'org-mime-org-buffer-htmlize)
  695. (local-set-key (kbd "C-c M-o") 'org-mime-org-buffer-htmlize))
  696. ;; (distopico:org-saveplace) TODO: check if already need it
  697. ;; Try when enable org-indent-mode again
  698. ;; (aggressive-indent-mode)
  699. ;; TODO enable for blogging, no enabled by default because
  700. ;; with tags indented does not look good, maybe disable tags
  701. ;; indentation is one option.
  702. ;; (visual-line-mode +1)
  703. (flyspell-mode +1)
  704. (add-hook 'completion-at-point-functions 'pcomplete-completions-at-point nil 'make-it-local)
  705. (add-hook 'before-save-hook 'distopico:org-before-save-hook nil 'make-it-local)
  706. (add-hook 'after-save-hook 'distopico:org-after-save-hook nil 'make-it-local))
  707. (defun distopico:org-after-save-hook ()
  708. "Hook for after save in `org-mode'."
  709. (when (eq major-mode 'org-mode)
  710. (distopico:org-run-appt)
  711. (distopico:org:remove-empty-propert-drawers)
  712. (org-save-all-org-buffers)
  713. (message (concat "Wrote " (buffer-file-name)))))
  714. (defun distopico:org-before-save-hook ()
  715. "Hook for before save in `org-mode'."
  716. (when (eq major-mode 'org-mode)
  717. (and buffer-file-name
  718. (file-exists-p buffer-file-name)
  719. (distopico:org-remove-redundant-tags))
  720. (org-align-tags t)
  721. (org-update-all-dblocks)))
  722. (defun distopico:org-capture-mode-hook ()
  723. "Hook for `org-capture-mode'."
  724. (flyspell-mode +1)
  725. ;; Capture to be the only window when used as a popup.
  726. (if (equal "emacs-capture" (frame-parameter nil 'name))
  727. (delete-other-windows)))
  728. (defun distopico:org-capture-before-finalize-hook ()
  729. "Hook for capture before finalized in`org-mode'."
  730. (org-align-tags))
  731. (defun distopico:org-capture-after-finalize-hook ()
  732. "Hook for capture after finalized in`org-mode'."
  733. (if (equal "emacs-capture" (frame-parameter nil 'name))
  734. (delete-frame))
  735. (distopico:org-update-agenda-views))
  736. (defun distopico:org-init-load-hook ()
  737. "Hook when Emacs load."
  738. (distopico:org-run-appt)
  739. (org-notify-start))
  740. (defun distopico:org-after-todo-state-change-hook ()
  741. "Hook after a todo state change happens."
  742. (distopico:org-toggle-next-tag)
  743. (distopico:org-insert-trigger))
  744. ;; Hooks
  745. (add-hook 'org-mode-hook 'distopico:org-init-hook)
  746. (add-hook 'org-after-todo-state-change-hook #'distopico:org-after-todo-state-change-hook 'append)
  747. (add-hook 'midnight-hook 'distopico:org-show-agenda-appt 'append)
  748. (add-hook 'distopico:after-init-load-hook #'distopico:org-init-load-hook)
  749. (with-eval-after-load 'org-capture
  750. (add-hook 'org-capture-mode-hook #'distopico:org-capture-mode-hook 'append)
  751. (add-hook 'org-capture-before-finalize-hook #'distopico:org-capture-before-finalize-hook 'append)
  752. (add-hook 'org-capture-after-finalize-hook #'distopico:org-capture-after-finalize-hook 'append))
  753. (with-eval-after-load 'org-clock
  754. (org-clock-persistence-insinuate)
  755. (add-hook 'org-clock-in-hook
  756. (lambda ()
  757. (pomodoro)
  758. (add-hook 'pomodoro-break-finished-hook 'org-clock-in-last)
  759. (add-hook 'pomodoro-finished-hook 'org-clock-out)
  760. (distopico:org-clock-in-set-state-to-started)) 'append)
  761. (add-hook 'org-clock-out-hook
  762. (lambda ()
  763. (distopico:remove-empty-drawer-on-clock-out)) 'append)
  764. (add-hook 'org-clock-cancel-hook
  765. (lambda ()
  766. (pomodoro-stop)
  767. (remove-hook 'pomodoro-break-finished-hook 'org-clock-in-last)
  768. (remove-hook 'pomodoro-finished-hook 'org-clock-out)
  769. (distopico:remove-empty-drawer-on-clock-out)) 'append))
  770. (provide 'conf-org)
  771. ;;; conf-org.el ends here