aboutsummaryrefslogtreecommitdiffstats
path: root/oni-org/oni-org.el
diff options
context:
space:
mode:
Diffstat (limited to 'oni-org/oni-org.el')
-rw-r--r--oni-org/oni-org.el214
1 files changed, 214 insertions, 0 deletions
diff --git a/oni-org/oni-org.el b/oni-org/oni-org.el
new file mode 100644
index 0000000..4ba4506
--- /dev/null
+++ b/oni-org/oni-org.el
@@ -0,0 +1,214 @@
+;;; oni-org.el --- Org mode configuration -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2019 Tom Willemse
+
+;; Author: Tom Willemse <tom@ryuslash.org>
+;; Keywords: local
+;; Version: 20190827234011
+;; Package-Requires: (oni-yasnippet org-plus-contrib org-bullets hydra org-wild-notifier)
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; Configuration for `org-mode'.
+
+;;; Code:
+
+(require 'hydra)
+(require 'org)
+(require 'org-capture)
+(require 'org-clock)
+(require 'org-habit)
+(require 'yasnippet)
+
+(defconst oni-org-root
+ (file-name-directory
+ (or load-file-name
+ (buffer-file-name)))
+ "The directory where ‘oni-org’ was loaded from.")
+
+(defconst oni-org-snippets-dir
+ (expand-file-name "snippets" oni-org-root)
+ "The directory where ‘oni-org’ stores its snippets.")
+
+(defun oni-org-expand-to-home (file-name)
+ "Expand FILE-NAME to the base directory for that system.
+The base for all org files on Windows is u:/, but on my linux
+installs it will always be ~."
+ (let ((base-dir (if (eq system-type 'windows-nt) "u:/" "~")))
+ (expand-file-name file-name base-dir)))
+
+(defun oni-org-setup-prettify-symbols-mode ()
+ "Set up prettify symbols mode for org mode."
+ (when (member "Ionicons" (font-family-list))
+ (setq-local prettify-symbols-alist
+ '(("[ ]" . #xf372)
+ ("[X]" . #xf374)))
+ (set-face-attribute 'org-checkbox nil :family "Ionicons")
+ (prettify-symbols-mode)))
+
+(defun oni-org-heading-has-predecessor-p ()
+ "Determine if the heading at point has any predecessors.
+Only tasks of a level greater than 3 are considered. A task has a
+predecessor if there is a non-DONE sibling defined before it."
+ (let ((point (point)))
+ (save-excursion
+ (org-backward-heading-same-level 1 :invisible-ok)
+ (seq-let [level _ keyword] (org-heading-components)
+ (not (or (< level 3)
+ (= point (point))
+ (member keyword org-done-keywords)))))))
+
+(defun oni-org-looking-for-tag-p (tag)
+ "Return t if we're currently looking for TAG in an agenda."
+ (and (eql 'org-tags-view (car org-agenda-redo-command))
+ (string-match-p (rx-to-string `(and word-start ,tag word-end))
+ org-agenda-query-string)))
+
+(defun oni-org-next-heading-position ()
+ "Get the position of the next Org heading."
+ (or (ignore-errors
+ (org-forward-element)
+ (point))
+ (point-max)))
+
+(defun oni-org-skip-tasks ()
+ "Skip over tasks I don't want to see right now.
+Tasks being skipped over include ones with the \"ex\" tag and
+ones that have a predecessor."
+ (let ((tags (org-get-tags (point))))
+ (when (or (and (not (oni-org-looking-for-tag-p "ex"))
+ (member "ex" tags))
+ (oni-org-heading-has-predecessor-p))
+ (oni-org-next-heading-position))))
+
+;;;###autoload
+(defun oni-org-snippets-initialize ()
+ "Initialize the snippets for ‘oni-org’."
+ (when (boundp 'yas-snippet-dirs)
+ (add-to-list 'yas-snippet-dirs oni-org-snippets-dir t))
+ (yas-load-directory oni-org-snippets-dir))
+
+(defun oni-org-delete-frame-once ()
+ "Run `delete-frame'.
+
+After running it once remove it from `org-capture-after-finalize-hook'."
+ (delete-frame)
+ (remove-hook 'org-capture-after-finalize-hook 'oni-org-delete-frame-once))
+
+(defun oni-org-run-capture-in-dedicated-frame ()
+ "Run `org-capture' in a dedicated frame."
+ (with-selected-frame (make-frame '((minibuffer)))
+ (org-capture nil "t")
+ (delete-other-windows)
+ (setf (frame-width) 80)
+ (setf (frame-height) 24)
+ (add-hook 'org-capture-after-finalize-hook 'oni-org-delete-frame-once)))
+
+(defun oni-org-maybe-change-todo-state (current-state)
+ "Change the state of the current task to in-progress CURRENT-STATE is todo."
+ (if (string= current-state "TODO")
+ "IN-PROGRESS"
+ current-state))
+
+;;;###autoload
+(defun oni-org-open-index ()
+ "Open the index of my org-based personal wiki."
+ (interactive)
+ (find-file (oni-org-expand-to-home "documents/gtd/index.org")))
+
+;;;###autoload(autoload 'oni-hydra-org/body "oni-org")
+(defhydra oni-hydra-org (:color blue)
+ "Org"
+ ("l" org-store-link "Store link")
+ ("a" org-agenda "Agenda")
+ ("c" org-capture "Capture")
+ ("b" org-switchb "Switch to org buffer"))
+
+(setq org-default-notes-file
+ (oni-org-expand-to-home "documents/gtd/inbox.org"))
+(setq org-src-fontify-natively t)
+(setq org-return-follows-link t)
+(setq org-fontify-whole-heading-line t)
+(setq org-hide-emphasis-markers t)
+(setq org-return-follows-link t)
+(setq org-use-fast-todo-selection t)
+(setq org-log-into-drawer t)
+(setq org-agenda-todo-ignore-scheduled 'future)
+(setq org-agenda-skip-function-global #'oni-org-skip-tasks)
+(setq org-clock-in-switch-to-state #'oni-org-maybe-change-todo-state)
+
+(setq org-agenda-custom-commands
+ '(("c" "Today's (Current) tasks" tags "SCHEDULED=\"<today>\"")))
+
+(setq org-agenda-files
+ (mapcar #'oni-org-expand-to-home
+ '("documents/gtd/todo.org"
+ "documents/gtd/projects.org"
+ "documents/gtd/appointments.org")))
+
+(setq org-refile-targets
+ (mapcar (lambda (pair)
+ (cons (oni-org-expand-to-home (car pair))
+ (cdr pair)))
+ '(("documents/gtd/todo.org" :maxlevel . 1)
+ ("documents/gtd/projects.org" :level . 2)
+ ("documents/gtd/someday.org" :maxlevel . 1)
+ ("documents/gtd/appointments.org" :maxlevel . 1)
+ ("documents/gtd/music.org" :maxlevel . 1)
+ ("documents/gtd/books.org" :maxlevel . 1))))
+
+(setq org-capture-templates
+ `(("t" "Note" entry
+ (file ,(oni-org-expand-to-home "documents/gtd/inbox.org"))
+ "* TODO %i%?\n :PROPERTIES:\n :CREATED: %U\n :END:")
+ ("a" "Appointment" entry
+ (file+headline ,(oni-org-expand-to-home "documents/gtd/appointments.org")
+ "Appointments")
+ "* TODO %i%?\n %U")
+ ("j" "Journal entry" entry
+ (file+olp+datetree
+ ,(oni-org-expand-to-home "documents/gtd/journal.org"))
+ "* %<%H:%M:%S>\n %?")))
+
+(setq org-todo-keywords
+ '((sequence "TODO(t)" "BLOCKED(b@)" "IN-PROGRESS(p)"
+ "|" "DONE(d!)" "CANCELLED(c@)")))
+
+(add-to-list 'org-modules 'org-habit)
+(add-to-list 'org-modules 'org-tempo)
+
+(add-hook 'org-mode-hook 'auto-fill-mode)
+
+(unless (eq system-type 'windows-nt)
+ (require 'org-bullets)
+ (add-hook 'org-mode-hook 'org-bullets-mode)
+ (add-hook 'org-mode-hook #'oni-org-setup-prettify-symbols-mode))
+
+;;;###autoload
+(global-set-key (kbd "C-c o") 'oni-hydra-org/body)
+
+;;;###autoload
+(global-set-key (kbd "C-<home>") #'oni-org-open-index)
+
+;;;###autoload
+(with-eval-after-load 'org
+ (with-eval-after-load 'yasnippet
+ (oni-org-snippets-initialize)))
+
+;;;###autoload(with-eval-after-load 'org (require 'oni-org))
+
+(provide 'oni-org)
+;;; oni-org.el ends here