;; -*- 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. Iā€™m 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")) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; pomidor ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (use-package pomidor :bind (("C-w P" . pomidor)) :config (setq pomidor-update-interval 30 pomidor-alert nil pomidor-sound-tick nil pomidor-sound-tack nil pomidor-sound-overwork nil pomidor-sound-break-over nil) :hook (pomidor-mode . (lambda () (display-line-numbers-mode -1) ; Emacs 26.1+ (setq left-fringe-width 0 right-fringe-width 0) (setq left-margin-width 2 right-margin-width 0) ;; force fringe update (set-window-buffer nil (current-buffer))))) ; setup 6 pomodoros for 8 hr work day ; 7 hours of work, with 1 hr of long breaks ; each pomodor is: ; warm up of 15 mins ; work of 45 mins ; total work period: 60 mins ; 10 min break ; total interval period: 70 mins ; long break is 30 mins ; every 3rd pomodoro give 30 minute break (setq pomidor-seconds (* 60 60)) ; total work period (setq pomidor-warmup-seconds (* 15 60)) ; warmup time (setq pomidor-break-seconds (* 10 60)) (setq pomidor-breaks-before-long 3) (setq pomidor-long-break-seconds (* 30 60)) (defun my-pomidor-update-hook () (let* ((state (pomidor--current-state)) (total (pomidor--total-duration state)) (ellapsed (round (time-to-seconds total)))) (if (<= ellapsed pomidor-warmup-seconds) (setq pomidor-header-separator " šŸŒ”ļøā†‘ ") (setq pomidor-header-separator " ā€” ") ) ) ) (add-hook 'pomidor-update-hook #'my-pomidor-update-hook) ; pop win pomidor setup ; main way to invoke ; ensure pomidor is running before trying to open the buffer ; use global buffer name for pomidor ; make the popwin window 'sticky' ; position sticky popwin @ top (push '(pomidor-mode :position top :stick t) popwin:special-display-config) (global-set-key (kbd "C-w p") (lambda () (interactive) ; make sure pomidor is running + active w/o resetting the current state (when (or (not (boundp 'pomidor-buffer-name)) (not (get-buffer pomidor-buffer-name))) (pomidor) (previous-buffer) ; pomidor switches buffers -- go back to orig buffer ) ; open pomidor in popwin (popwin:display-buffer (get-buffer pomidor-buffer-name)) ) ) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; 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 "") #'origami-toggle-node) (define-key org-agenda-mode-map (kbd "") #'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 '(pomidor (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))