Say my name, say my name
(setq user-full-name "Duncan Mbuli-Robertson"
user-mail-address "duncanr19@gmail.com")
Disable annoying quit message and maximise on startup
(setq confirm-kill-emacs nil)
(add-to-list 'initial-frame-alist '(fullscreen . maximized))
Use free-keys package to check what keys are available
(use-package! free-keys)
Bind the local leader key to U and useful functions to C-c
(setq doom-localleader-key "U")
(map!
"C-c e" #'eval-region
"C-c r" #'org-refile
"C-c k" #'free-keys
"C-c c" #'org-schedule
)
Configure the fonts
(setq doom-font (font-spec :family "Iosevka" :size 18 :weight 'regular))
(custom-set-faces!
'(org-document-title :height 1.4)
'(org-level-1 :inherit outline-1 :weight extra-bold :height 1.25)
'(org-level-2 :inherit outline-2 :weight bold :height 1.15)
'(org-level-3 :inherit outline-3 :weight bold :height 1.12)
'(org-level-4 :inherit outline-4 :weight bold :height 1.09)
'(org-level-5 :inherit outline-5 :weight semi-bold :height 1.06)
'(org-level-6 :inherit outline-6 :weight semi-bold :height 1.03)
'(org-level-7 :inherit outline-7 :weight semi-bold)
'(org-level-8 :inherit outline-8 :weight semi-bold)
)
Configure the theme
(setq doom-theme 'doom-one)
(setq display-line-numbers-type nil)
Set pretty arrow to replace … as content in org header indication:
(setq org-ellipsis "⤵")
Define variable for the Dropbox directory to use in config
(defvar dmr/org-directory "/mnt/c/Users/duncanr/Dropbox/Org/")
Sync org files with Dropbox
(setq org-directory dmr/org-directory)
Set GTD style TODO keywords
(setq org-todo-keywords '((sequence "TODO(t)" "WAITING(w)" "NEXT(n)" "|" "DONE(d)" "CANCELLED(c)")))
Define function and binding to mark item as done/next and archive it: (from this dot file)
(defun dmr/mark-done-and-archive ()
"Mark the state of an org-mode item as DONE and archive it."
(interactive)
(org-todo 'done)
(org-archive-subtree))
(defun dmr/mark-done ()
"Mark the state of an org-mode item as DONE."
(interactive)
(org-todo 'done))
Now we can bind all our new functions to a new leader key menu
(map! :leader
:prefix "d"
:desc "dmr/mark-done-and-archive" "d" #'dmr/mark-done-and-archive
:desc "dmr/mark-done" "D" #'dmr/mark-done
)
(use-package org-roam-bibtex
:after org-roam)
Set Org Roam directory and basic keybindings
(use-package! org-roam
:init
(map! :leader
:prefix "n"
:desc "org-roam" "l" #'org-roam-buffer-toggle
:desc "org-roam-node-insert" "i" #'org-roam-node-insert
:desc "org-roam-node-find" "f" #'org-roam-node-find
:desc "org-roam-ref-find" "r" #'org-roam-ref-find
:desc "org-roam-show-graph" "g" #'org-roam-show-graph
)
(setq org-roam-directory (concat dmr/org-directory "roam")
org-roam-completion-everywhere t
)
)
Do not show clocked task in modeline
(setq org-clock-clocked-in-display nil)
Customise org-duration to calculate pomodoro counts from clocksums using this Stack Exchange answer with the updated org function, then set pomodoro count as an org-duration unit so that setting effort will work with pomodoro units
(defun dmr/org-minutes-to-clocksum-string (m)
"Format number of minutes as a clocksum string.
Shows the number of 25-minute pomodoros."
(format "%dp" (ceiling (/ m 25))))
(after! org-duration
(fset 'org-duration-from-minutes 'dmr/org-minutes-to-clocksum-string)
(push (cons "p" 25) org-duration-units)
(org-duration-set-regexps) ;NB: org-duration-units is not implemented otherwise!
)
Set effort in pomodoros, from this stack exchange thread:
(defun dmr/org-set-effort-in-pomodoros (&optional n)
(interactive "P")
(setq n (or n (string-to-number (read-from-minibuffer "How many pomodoros: " nil nil nil nil "1" nil))))
(let* ((mins-per-pomodoro-prop (org-entry-get (point) "MINUTES_PER_POMODORO" t))
(mins-per-pomodoro (if mins-per-pomodoro-prop
(string-to-number mins-per-pomodoro-prop)
25)))
(org-set-effort nil (org-duration-from-minutes (* n mins-per-pomodoro)))))
(map!
"C-c s" #'dmr/org-set-effort-in-pomodoros)
Set agenda files
(setq org-agenda-files (list "projects.org"
"habits.org"
))
Format agenda into columns
(setq org-agenda-view-columns-initially t)
(setq org-agenda-overriding-columns-format "%TODO %46ITEM %3Effort(E){:} %3CLOCKSUM(R) %20ALLTAGS")
Schedule task for today / unschedule
(defun dmr/schedule-for-today ()
(interactive)
(org-schedule nil "+0d"))
(defun dmr/unschedule ()
(interactive)
(org-schedule '(4)))
Agenda for today
(setq org-agenda-start-day nil)
(setq org-agenda-custom-commands
`(("1" "Today" agenda "" (
(org-agenda-ndays 1)
(org-agenda-span 1)
)))
)
(defun dmr/agenda-today (&optional arg)
(interactive "P")
(org-agenda arg "1"))
(map! :leader
(:prefix "d"
:desc "Schedule for today" "0" #'dmr/schedule-for-today
:desc "Unschedule" "u" #'dmr/unschedule
:desc "Agenda for today" "a" #'dmr/agenda-today
))
(setq org-capture-templates '(
("i" "Inbox" entry (file "inbox.org")
"* TODO %?\n%U")
("p" "Project" entry
(file "projects.org")
"* %^{Project name} :%\\1: \n:PROPERTIES:\n:ARCHIVE: archive.org::* %\\1\n:END:")
("h" "Habit" entry
(file "habits.org")
"* TODO %i%?\n:PROPERTIES:\n:STYLE: habit\n:END:")
))
Set org-refile targets
(setq org-refile-targets '(("projects.org" :level . 1)
("someday.org" :level . 1)
("habits.org" :level . 0)
))
Archive everything into a single file:
(setq org-archive-location (concat dmr/org-directory "archive.org::"))
Set the directory for journal files:
(setq org-journal-dir (concat dmr/org-directory "journal"))
Format journal files and headings nicely
(setq org-journal-file-format "%Y-%m-%d.org"
org-journal-date-prefix "* "
org-journal-date-format "%A, %B %d %Y")
Make first heading be level 2, with timestamp (%R = current time)
(setq org-journal-time-prefix "** "
org-journal-time-format "%R: ")
Bind general leader key shortcut to open today’s journal without adding new entry:
- ‘(4) makes it call the function with a prefix argument, which prevents a new entry from being made.
- Also bind key to make new journal entry.
(defun dmr/open-todays-journal ()
(interactive)
(progn
(org-journal-new-entry '(4))
(outline-show-all)
))
(defun dmr/journal-new-entry ()
(interactive)
(progn
(org-journal-new-entry nil)
(evil-insert-state))
)
(map! :leader
(:prefix ("j" . "journal") ;; org-journal bindings
:desc "Create new journal entry" "j" #'dmr/journal-new-entry
:desc "Open today's journal" "J" #'dmr/open-todays-journal
:desc "Open previous entry" "p" #'org-journal-previous-entry
:desc "Open next entry" "n" #'org-journal-next-entry
:desc "Search journal" "s" #'org-journal-search-forever
))
(map!
(:map calendar-mode-map
:n "o" #'org-journal-display-entry
:n "p" #'org-journal-previous-entry
:n "n" #'org-journal-next-entry
:n "O" #'org-journal-new-date-entry))
I want journal entries to still be in org-mode, since org-journal-mode doesn’t have the org-mode leader key menu, and I can make special bindings anyway. First, we enable auto-fill-mode
(add-hook 'org-journal-mode-hook 'auto-fill-mode)
(add-hook 'org-journal-mode-hook 'org-mode)
'(org-edit-src-content-indentation 0)
'(org-src-preserve-indentation nil)
Now we can open projects, inbox and agenda whenever we launch emacs
(defun dmr/find-projects ()
(interactive)(find-file (concat dmr/org-directory "projects.org")))
(defun dmr/find-inbox ()
(interactive)(find-file (concat dmr/org-directory "inbox.org")))
;; (defun dmr/open-gtd-buffers ()
;; (interactive)
;; (progn
;; (doom/window-maximize-buffer)
;; (let ((projectile-switch-project-action 'dmr/find-projects))
;; (print projectile-switch-project-action)
;; (projectile-switch-project-by-name dmr/org-directory)
;; )
;; (evil-window-split)
;; (dmr/find-inbox)
;; (+workspace-rename "main" "Org")
(defun dmr/open-org-workspace ()
(interactive)
(if (+workspace-exists-p "Org")
(+workspace-switch "Org")
(+workspace/load "Org")
))
(map! :leader
:prefix "d"
:desc "dmr/find-inbox" "i" #'dmr/find-inbox
:desc "dmr/open-org-workspace" "p" #'dmr/open-org-workspace
)
(use-package! eval-in-repl
:after python
:config
(require 'eval-in-repl-python)
(define-key global-map (kbd "C-<return>") nil)
(define-key global-map (kbd "C-RET") nil)
(define-key evil-insert-state-map (kbd "C-RET") nil)
(define-key evil-normal-state-map (kbd "C-RET") nil)
(define-key evil-normal-state-map (kbd "C-<return>") nil)
(map! :after python
:map python-mode-map
"C-<return>" #'eir-eval-in-python)
(setq eir-repl-placement 'right)
)
Set up snakemake-mode
(use-package! snakemake-mode
:after python
:config
)
;; (defun dmr/open-gtd-buffers ()
;; (interactive)
;; (progn
;; (ess-eval-region-or-function-or-paragraph-and-step)
;; (pop-to-buffer "*R*")
;; (evil-goto-line)
;; ))
(map! :after ess-mode
:map ess-mode-map
"<normal-state> C-<return>" #'ess-eval-region-or-function-or-paragraph-and-step
"C-<return>" #'ess-eval-region-or-function-or-paragraph-and-step
"C-RET" nil)
(map! :after ess-mode
:map ess-doc-map
"<normal-state> C-<return>" #'ess-eval-region-or-function-or-paragraph-and-step
"C-<return>" #'ess-eval-region-or-function-or-paragraph-and-step
"C-RET" nil)