emacs/org/init.el
2024-08-02 13:33:29 -04:00

403 lines
18 KiB
EmacsLisp
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

;; -*- lexical-binding: t; -*-
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; windows performance tweaks
(when (eq system-type 'windows-nt)
; https://lists.gnu.org/archive/html/bug-gnu-emacs/2012-10/msg00274.html
; https://gioorgi.com/2013/solving-emacs-freeze-andor-slowdown-on-windows7/
(setq w32-get-true-file-attributes nil)
; https://www.reddit.com/r/emacs/comments/c9ef5i/comment/esx5ndr/
(setq inhibit-compacting-font-caches t)
; https://www.reddit.com/r/emacs/comments/c9ef5i/comment/esx5snw/
(when (boundp 'w32-pipe-read-delay)
(setq w32-pipe-read-delay 0))
)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; misc performance tweaks
;; Make gc pauses faster by decreasing the threshold.
(setq gc-cons-threshold (* 2 1000 1000))
;; disable warnings from popping up, they are still logged
(setq warning-suppress-types '((comp)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; helper functions
;; Figure out if inside Termux
(require 'subr-x)
(setq kmn/is-termux
(string-suffix-p "Android" (string-trim (shell-command-to-string "uname -a"))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; os specific config
(when (and (eq system-type 'windows-nt)
(not kmn/is-termux))
; Fix resolution of ~ to match other client paths
(setenv "HOME" "C:/Users/mcros/Nextcloud")
(setq default-directory "C:/Users/mcros/Nextcloud")
; add executables to path ahead of them being used by extensions / emacs stuff
(add-to-list 'exec-path "C:/Users/mcros/OneDrive/Programs/PortableApps/sqlite3")
(add-to-list 'exec-path "C:/msys64/usr/bin/unzip.exe")
(setenv "PATH" (concat "C:\\msys64\\mingw64\\bin;" (getenv "PATH")))
)
(when kmn/is-termux
; setup storage locations -- cheat so mobile/desktop look alike for file urls
;(setq user-init-file "/data/data/com.termux/files/home/storage/shared/.emacs")
;(setq user-emacs-directory "/data/data/com.termux/files/home/storage/shared/.emacs.d/")
;(setenv "HOME" "/data/data/com.termux/files/home/storage/shared/")
;(load user-init-file)
; Fix resolution of ~ to match other client paths
(setenv "HOME" "/data/data/com.termux/files/home/")
(setq default-directory "/data/data/com.termux/files/home/")
; Setup xdg-open as the default for opening files (except for the few we want emacs to open native)
; xdg-open is linked to termux-open by default ; if you need 'more' look into tmux-open and adjust accordingly
; (add-to-list 'org-file-apps '("\\.doc.*" . "open %s"))
(setq org-file-apps
'(;; default
(auto-mode . emacs)
("\\.org" . emacs)
("\\.txt" . emacs)
(".*" . "termux-open --chooser --view %s")))
)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; global config
(load "~/.emacs.d.profiles/common/_global.el")
(load "~/.emacs.d.profiles/common/generic_functions.el")
(load "~/.emacs.d.profiles/common/workspaces.el")
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; compile bytecode for this profile
(unless (was-compiled-p "~/.emacs.d.profiles/org")
(byte-recompile-directory "~/.emacs.d.profiles/org" 0))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; additional packages
(add-to-list 'package-selected-packages
'(org-tidy org-auto-expand ox-pandoc ox-hugo org-super-agenda org-alert burnt-toast alert)
)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Load misc extensions
(require 'org)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; org-alert - windows only
(when (eq system-type 'windows-nt)
(use-package org-alert)
(use-package burnt-toast
:config
(require 'burnt-toast-alert)
(setq alert-default-style 'burnt-toast)
)
(setq org-alert-interval 300
org-alert-notify-cutoff 5
org-alert-notify-after-event-cutoff 5)
(org-alert-enable)
)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Update/add auto file handling
(add-to-list 'auto-mode-alist '("\\.org\\'" . org-mode))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; hide property drawers / minimize them
(use-package org-tidy
:ensure t
:config
(setq org-tidy-top-property-style 'keep)
(setq org-tidy-properties-style 'inline)
(setq org-tidy-properties-inline-symbol "")
(setq org-tidy-property-drawer-flag t)
;org-tidy-property-drawer-property-whitelist
(setq org-tidy-property-drawer-property-blacklist '("TIDY_DISABLE" "TIDY_OFF"))
(setq org-tidy-general-drawer-flag t)
;org-tidy-general-drawer-name-whitelist
;org-tidy-general-drawer-name-blacklist
:hook
(org-mode . org-tidy-mode))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; keyboard shortcuts
(load "~/.emacs.d.profiles/org/config-org-keyboard.el")
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Set some orgmode config
(defun my/org_timestamp ()
(interactive)
(org-insert-time-stamp (current-time) (current-time) "t")
)
(org-defkey org-mode-map (kbd "C-c !") #'my/org_timestamp)
(setq org-startup-folded t)
(setq org-return-follows-link t)
(setq org-startup-folded t)
(setq org-support-shift-select t)
(setq org-log-into-drawer t)
(setq org-log-done t)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; automatic ids for everything
; From https://web.archive.org/web/20220512120917/https://stackoverflow.com/questions/13340616/assign-ids-to-every-entry-in-org-mode
; From https://stackoverflow.com/questions/13340616/assign-ids-to-every-entry-in-org-mode
; This hunk of lisp automatically adds IDs to every header in an org file when you hit save. it usese org-id which can generated IDs of various types including timestamps. Im using the default UUIDs
(defun stackoverflow/org-add-ids-to-headlines-in-file ()
"cargo cult from stackoverflow to add ids"
(interactive)
(org-map-entries 'org-id-get-create)
)
(add-hook 'org-mode-hook
(lambda ()
(add-hook 'before-save-hook 'stackoverflow/org-add-ids-to-headlines-in-file nil 'local)))
(add-hook 'org-capture-prepare-finalize-hook 'org-id-get-create)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; keep 'ARCHIVE' property up to date for entire buffer so any archives are filed in 'todays' archive
; assumes you want archive dates to be the date of the archive operation, not the last time they were 'touched' (or created)
(defun kmn/org-set-archive-prop-for-todo ()
(interactive)
(save-excursion
(goto-char (point-max))
(while (outline-previous-heading)
(org-set-property "ARCHIVE" (concat
"~/org/Attic/org-mode/%s/"
(format-time-string "%Y" (current-time))
"/"
(format-time-string "%m" (current-time))
".archive.org::datetree/"
))
))
)
(add-hook 'org-mode-hook
(lambda ()
(add-hook 'before-save-hook 'kmn/org-set-archive-prop-for-todo nil 'local)))
(add-hook 'org-capture-prepare-finalize-hook 'kmn/org-set-archive-prop-for-todo)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; ox-hugo for blog
(with-eval-after-load 'ox (require 'ox-hugo))
(with-eval-after-load 'ox-hugo
(setq org-hugo-link-desc-insert-type t)
(setq org-hugo-default-static-subdirectory-for-externals "ox-hugo" )
(setq org-hugo-external-file-extensions-allowed-for-copying '(
"jpg" "jpeg" "tiff" "png" "svg" "gif" "psd" "psb" "kra" "gpl"
"mp4"
"pdf" "odt"
"doc" "ppt" "xls"
"docx" "pptx" "xlsx"
"zip"
"xml"))
)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; org-mode todo tuning
; the ! tells org to log state changes for todo entries
(setq org-todo-keywords
'((sequence "TODO(t!)" "READY(r!)" "WIP(w!)" "|" "SKIPPED(k!)" "COMPLETE(c!)" "CANCELED(x!)"))
)
(setq org-todo-keyword-faces
'(("TODO" . "turquoise") ("READY" . "yellow") ("WIP" . "magenta") ("COMPLETE" . "green") ("CANCELED" . "orange"))
)
; log to drawer of entry
(setq org-log-into-drawer t)
(setq org-treat-insert-todo-heading-as-state-change t)
; set completion stats to auto-calc for checkboxes and nested todo's
(setq org-provide-todo-statistics t)
(setq org-checkbox-hierarchical-statistics nil)
(setq org-hierarchical-todo-statistics nil)
; From https://christiantietze.de/posts/2021/02/emacs-org-todo-doing-done-checkbox-cycling/
; Ensure the uppermost todo, in a nested tree, has an appropriate status based on all sub-items in the tree
; Basically: - can only be marked 'complete' if all sub-items are in a completed state
; - auto-marked as 'todo' if no sub-items are complete
; - auto-marked as 'wip' if some sub-items are complete
; - auto-marked as 'complete' if all sub-items are complete
(defun org-todo-if-needed (state)
"Change header state to STATE unless the current item is in STATE already."
(unless (string-equal (org-get-todo-state) state)
(org-todo state)))
(defun ct/org-summary-todo-cookie (n-done n-not-done)
"Switch header state to DONE when all subentries are DONE, to TODO when none are DONE, and to DOING otherwise"
(let (org-log-done org-log-states) ; turn off logging
(org-todo-if-needed (cond ((= n-done 0)
"TODO")
((= n-not-done 0)
"COMPLETE")
(t
"WIP")))))
(add-hook 'org-after-todo-statistics-hook #'ct/org-summary-todo-cookie)
(defun ct/org-summary-checkbox-cookie ()
"Switch header state to DONE when all checkboxes are ticked, to TODO when none are ticked, and to DOING otherwise"
(let (beg end)
(unless (not (org-get-todo-state))
(save-excursion
(org-back-to-heading t)
(setq beg (point))
(end-of-line)
(setq end (point))
(goto-char beg)
;; Regex group 1: %-based cookie
;; Regex group 2 and 3: x/y cookie
(if (re-search-forward "\\[\\([0-9]*%\\)\\]\\|\\[\\([0-9]*\\)/\\([0-9]*\\)\\]"
end t)
(if (match-end 1)
;; [xx%] cookie support
(cond ((equal (match-string 1) "100%")
(org-todo-if-needed "COMPLETE"))
((equal (match-string 1) "0%")
(org-todo-if-needed "TODO"))
(t
(org-todo-if-needed "WIP")))
;; [x/y] cookie support
(if (> (match-end 2) (match-beginning 2)) ; = if not empty
(cond ((equal (match-string 2) (match-string 3))
(org-todo-if-needed "COMPLETE"))
((or (equal (string-trim (match-string 2)) "")
(equal (match-string 2) "0"))
(org-todo-if-needed "TODO"))
(t
(org-todo-if-needed "WIP")))
(org-todo-if-needed "WIP"))))))))
(add-hook 'org-checkbox-statistics-hook #'ct/org-summary-checkbox-cookie)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; tags
(load "~/.emacs.d.profiles/org/config-org-tags")
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; files
(setq org-default-notes-file "~/org/_index.org")
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; agendas
(load "~/.emacs.d.profiles/org/config-org-agendas.el")
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; capture templates
(load "~/.emacs.d.profiles/org/config-org-capture.el")
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; org-habit
(add-to-list 'org-modules 'org-habit)
(setq org-habit-preceding-days 14)
(setq org-habit-following-days 7)
(setq org-agenda-span 1)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; helm specific org adjustments
(load "~/.emacs.d.profiles/common/helm-org.el")
(require 'helm-org)
(helm-mode 1)
(add-to-list 'helm-completing-read-handlers-alist '(org-capture . helm-org-completing-read-tags))
(add-to-list 'helm-completing-read-handlers-alist '(org-set-tags . helm-org-completing-read-tags))
(add-to-list 'helm-completing-read-handlers-alist '(org-set-tags-command . helm-org-completing-read-tags))
; fix helm multi-tag select (needs custom seprator. default is comma
;(setq helm-crm-default-separator ":"
(define-advice helm--completion-in-region (:around (helm-fun origfun start end collection &optional predicate) temporary-helm-crm-separator-for-tags)
(setq tcrmds helm-crm-default-separator)
;; If the last command was any of these values, we're looking at tags most likely
(when (or (member last-command '(org-capture org-ctrl-c-ctrl-c org-set-tags org-set-tags-command))
;;This is a workaround for completions when you've already started typing.
(and (eq this-command 'crm-complete)
(eq major-mode 'org-mode))
;; This is probably the only thing we really need, but it doesn't handle custom "Tags" prompts
(and (active-minibuffer-window)
(eq "Tags: " (minibuffer-prompt))))
(setq helm-crm-default-separator ":"))
;; Call the original Helm Completion function with all the original arguments
(funcall helm-fun origfun start end collection predicate)
(setq helm-crm-default-separator tcrmds))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; ui tuning
(when (eq system-type 'windows-nt)
(load "~/.emacs.d.profiles/org/config-org-desktop.el"))
(when kmn/is-termux
(load "~/.emacs.d.profiles/org/config-org-mobile.el"))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; origami + super agenda config
(defvar ap/org-super-agenda-auto-hide-groups
'(".*Low Priority.*" "^.*?[^R]+.*?(desc)$"))
(defun ap/org-super-agenda-origami-fold-default ()
"Fold certain groups by default in Org Super Agenda buffer."
(--each ap/org-super-agenda-auto-hide-groups
(goto-char (point-min))
(cl-loop
while (re-search-forward it nil t)
do
(if (not (or
(string-match "TODO" (thing-at-point 'line))
(string-match "READY" (thing-at-point 'line))
(string-match "WIP" (thing-at-point 'line))
))
(origami-close-node (current-buffer) (point))
)
)
)
)
(add-hook 'org-agenda-mode-hook #'origami-mode)
(add-hook 'org-agenda-finalize-hook #'ap/org-super-agenda-origami-fold-default)
(define-key org-super-agenda-header-map (kbd "<tab>") #'origami-toggle-node)
(define-key org-agenda-mode-map (kbd "<tab>") #'origami-toggle-node)
(custom-set-faces
;; custom-set-faces was added by Custom.
;; If you edit it by hand, you could mess it up, so be careful.
;; Your init file should contain only one such instance.
;; If there is more than one, they won't work right.
'(default ((t (:family "MonoLisa Variable" :height 100))))
'(fixed-pitch ((t (:family "MonoLisa Variable" :height 120))))
'(variable-pitch ((t (:family "Atkinson Hyperlegible" :height 120)))))
(custom-set-variables
;; custom-set-variables was added by Custom.
;; If you edit it by hand, you could mess it up, so be careful.
;; Your init file should contain only one such instance.
;; If there is more than one, they won't work right.
'(custom-safe-themes
'("dde643b0efb339c0de5645a2bc2e8b4176976d5298065b8e6ca45bc4ddf188b7" "bfc0b9c3de0382e452a878a1fb4726e1302bf9da20e69d6ec1cd1d5d82f61e3d" default))
'(package-selected-packages
'((org-tidy org-auto-expand ox-pandoc ox-hugo org-super-agenda org-alert burnt-toast alert)
(devdocs devdocs-browser magit helm-ls-git xclip)
(which-key all-the-icons revert-buffer-all centaur-tabs scratch persistent-scratch persp-mode rainbow-mode rainbow-delimiters markdown-mode focus zoom popwin dired-single diredfl doominhibitinhibit-modeline helpful helm helm-org dired-rainbow dired-rainbow-listing dired-single dash s origami modus-themes use-package)))
'(safe-local-variable-values
'((org-auto-expand-nodes
(("To Do")
body 1)
(("Daily / Weekly Reset")
children 2))
(org-auto-expand-nodes
(("Daily / Weekly Reset")
body 2))
(eval org-auto-expand)
(org-auto-expand-nodes
(("To Do")
body 1))
(eval setq org-html-postamble nil)
(eval setq org-export-html-postamble-format nil)
(eval add-hook 'after-save-hook 'org-pandoc-export-to-latex-pdf t t)
(eval add-hook 'after-save-hook 'org-pandoc-export-to-docx t t)
(eval add-hook 'after-save-hook 'org-ascii-export-to-ascii t t)
(eval add-hook 'after-save-hook 'org-md-export-to-markdown t t)
(eval add-hook 'after-save-hook 'org-org-export-to-org t t)
(eval add-hook 'after-save-hook 'org-html-export-to-html t t)
(eval add-hook 'after-save-hook 'org-gfm-export-to-markdown t t)))
'(temp-buffer-resize-mode t)
'(zoom-ignored-major-modes '(dired-mode))
'(zoom-size 'kmn-zoom-size-callback))