diff options
Diffstat (limited to 'modules')
| -rw-r--r-- | modules/custom-functions.el | 3 | ||||
| -rw-r--r-- | modules/dirvish-config.el | 36 | ||||
| -rw-r--r-- | modules/eshell-vterm-config.el | 20 | ||||
| -rw-r--r-- | modules/flyspell-config.el | 7 | ||||
| -rw-r--r-- | modules/org-agenda-config.el | 425 | ||||
| -rw-r--r-- | modules/org-capture-config.el | 42 | ||||
| -rw-r--r-- | modules/org-config.el | 144 | ||||
| -rw-r--r-- | modules/org-roam-config.el | 174 | ||||
| -rw-r--r-- | modules/prog-general.el | 22 | ||||
| -rw-r--r-- | modules/prog-lisp.el | 10 | ||||
| -rw-r--r-- | modules/show-kill-ring.el | 11 | ||||
| -rw-r--r-- | modules/system-utils.el | 5 | ||||
| -rw-r--r-- | modules/test-code.el | 5 | ||||
| -rw-r--r-- | modules/ui-theme.el | 18 | ||||
| -rw-r--r-- | modules/vc-config.el | 9 |
15 files changed, 518 insertions, 413 deletions
diff --git a/modules/custom-functions.el b/modules/custom-functions.el index 9f1875a5..a36dfe80 100644 --- a/modules/custom-functions.el +++ b/modules/custom-functions.el @@ -438,7 +438,7 @@ Uses `sortable-time-format' for the formatting the date/time." (interactive) (insert (format-time-string sortable-time-format (current-time)))) -(defvar sortable-date-format "%Y-%m-%d " +(defvar sortable-date-format "%Y-%m-%d %a" "Time format to insert with `insert-current-time' func. See help of `format-time-string' for possible replacements") @@ -556,6 +556,7 @@ Uses `sortable-time-format' for the formatting the date/time." (define-key map "-" #'cj/hyphenate-region) (define-key map "U" 'upcase-region) (define-key map "w" 'cj/remove-leading-trailing-whitespace) + (define-key map "W" 'fixup-whitespace) (define-key map "#" 'cj/count-words-buffer-or-region) (define-key map "1" 'cj/alphabetize-and-replace-region) (define-key map "C" 'display-fill-column-indicator-mode) diff --git a/modules/dirvish-config.el b/modules/dirvish-config.el index f35d2934..12f67519 100644 --- a/modules/dirvish-config.el +++ b/modules/dirvish-config.el @@ -31,6 +31,35 @@ ;; (add-hook 'dired-mode-hook 'auto-revert-mode) ;; auto revert dired when files change +;; -------------------------- Dired Copy Path As Kill -------------------------- +;; copies the full path of the file at point to the clipboard + +(defun cj/dired-copy-path-as-kill () + "Copy the full path of file at point in dired to the clipboard." + (interactive) + (let ((filename (dired-get-file-for-visit))) + (if (and filename (file-exists-p filename)) + (progn + (kill-new filename) + (message "Copied '%s' to clipboard." filename)) + (message "No file at point.")))) + +;; ------------------------ Dired Convert Image To Jpeg ------------------------ +;; converts the image at point to a jpeg + +(defun cj/dired-convert-image-to-jpeg () + (interactive) + (let* ((original-file (dired-get-file-for-visit)) + (file-extension (file-name-extension original-file)) + (jpeg-file (concat (file-name-sans-extension original-file) ".jpeg"))) + (if (member file-extension '("png" "bmp" "gif" "tif" "tiff" "svg" "webp")) + (if (string= file-extension "jpeg") + (message "File is already in JPEG format.") + (start-process "convert-to-jpeg" nil "convert" original-file jpeg-file) + (message "Conversion started for %s" original-file)) + (message (concat "File is not a supported image file type." + "Current supported types: " + "'png' 'bmp' 'gif' 'tif' 'tiff' 'svg' 'webp'"))))) ;; ------------------------ Dired Mark All Visible Files ----------------------- ;; convenience function to mark all visible files in dired @@ -55,7 +84,8 @@ '(("h" "~/" "home") ("rsb" "/sshx:cjennings@wolf.usbx.me:/home/cjennings/" "remote seedbox") ("rcj" "/sshx:cjennings@cjennings.net:~" "remote cjennings.net") - ("co" "~/code" "code") + ("co" "~/code" "code") + ("cj" "~/code/cjennings-net" "cjennings.net hugo") ("df" "~/.dotfiles/" "dotfiles") ("dn" "~/downloads/" "downloads") ("dr" "~/sync/org/drill/" "org drill files") @@ -95,10 +125,12 @@ (shell-command (concat "nitrogen --save --set-zoom-fill " (dired-file-name-at-point) " >>/dev/null 2>&1" )))) ("Z" . (lambda () (interactive) (cj/open-file-with-command "zathura"))) - ("p" . (lambda () (interactive) (cj/open-file-with-command "gimp"))) + ("P" . (lambda () (interactive) (cj/open-file-with-command "gimp"))) ("<left>" . dired-up-directory) ("<right>" . dired-find-file) ("f" . dirvish-file-info-menu) + ("p" . cj/dired-copy-path-as-kill) + ("C" . cj/dired-convert-image-to-jpeg) ("y" . dirvish-yank-menu) ("N" . dirvish-narrow) ("M" . cj/dired-mark-all-visible-files) diff --git a/modules/eshell-vterm-config.el b/modules/eshell-vterm-config.el index 7d37d9e5..c6e5cc1e 100644 --- a/modules/eshell-vterm-config.el +++ b/modules/eshell-vterm-config.el @@ -65,20 +65,26 @@ (add-to-list 'eshell-visual-options '("git" "--help" "--paginate")) ;; aliases - (eshell/alias "clear" "clear 1") ;; leaves the prompt at the top of the window - (eshell/alias "e" "find-file $*") + (eshell/alias "clear" "clear 1") ;; leaves prompt at the top of the window + (eshell/alias "e" "find-file $1") (eshell/alias "gocj" "cd /sshx:cjennings@cjennings.net:/var/cjennings/") (eshell/alias "gosb" "cd /sshx:cjennings@wolf.usbx.me:/home/cjennings/") (eshell/alias "gowolf" "cd /sshx:cjennings@wolf.usbx.me:/home/cjennings/") (eshell/alias "v" "eshell-exec-visual $*") - (eshell/alias "ff" "find-file-other-window $*") - (eshell/alias "f" "cj/eshell-find-using-dired $1") + (eshell/alias "ff" "find-file-other-window $1") + (eshell/alias "f" "find-using-dired $1") (eshell/alias "r" "ranger") - (eshell/alias "em" "find-file $*") - (eshell/alias "emacs" "find-file $*") + (eshell/alias "em" "find-file $1") + (eshell/alias "emacs" "find-file $1") (eshell/alias "ll" "ls -l")))) -(defun cj/eshell-find-using-dired (file-pattern) +(defun eshell/find-file-other-window (file) + (find-file-other-window (mapconcat 'identity file " "))) + +(defun eshell/find-file (file) + (find-file-other-window (mapconcat 'identity file " "))) + +(defun eshell/find-using-dired (file-pattern) "Find a file FILE-PATTERN' using 'find-name-dired'." (let ((escaped-pattern (regexp-quote file-pattern))) (find-name-dired . escaped-pattern))) diff --git a/modules/flyspell-config.el b/modules/flyspell-config.el index 6109eebc..ad0945c4 100644 --- a/modules/flyspell-config.el +++ b/modules/flyspell-config.el @@ -180,12 +180,5 @@ handled appropriately." (global-set-key (kbd "C-c f") 'flyspell-toggle ) -;; -------------------------------- Ispell STFU -------------------------------- -;; tell ispell where to send it's spurious error messages - -(advice-add 'ispell-lookup-words :around - (lambda (orig &rest args) - (shut-up (apply orig args)))) - (provide 'flyspell-config) ;;; flyspell-config.el ends here. diff --git a/modules/org-agenda-config.el b/modules/org-agenda-config.el index 016fffcc..f15e5503 100644 --- a/modules/org-agenda-config.el +++ b/modules/org-agenda-config.el @@ -5,277 +5,216 @@ ;; Agenda views are tied to the F8 (fate) key. -;; f8 - DAILY SCHEDULE containing a events with a scheduled date or deadline of -;; the current day. This is followed by... -;; - TASK LIST containing tasks from all agenda sources. +;; f8 - MAIN AGENDA which organizes all tasks and events into: +;; - all unfinished priority A tasks +;; - the weekly schedule, including the habit consistency graph +;; - all priority B and C tasks -;; C-f8 - TASK LIST containing all tasks from all agenda sources +;; C-f8 - TASK LIST containing all tasks from all agenda targets. -;; M-f8 - TASK LIST containing all tasks from the current org-mode buffer. +;; M-f8 - TASK LIST containing all tasks from just the current org-mode buffer. ;; NOTE: ;; Files that contain information relevant to the agenda will be found in the ;; following places: the schedule-file, org-roam notes tagged as 'Projects' and ;; project todo.org files found in project-dir and code-dir. -;; How the agenda is created: -;; The inbox and schedule files are always included first. However, in order to -;; stay current, the files containing agenda information are queried before -;; calling the functions in the section org-agenda functions to display the -;; data. This way, any newly created events from project todo.org files, or -;; org-roam Project files will be included. - ;;; Code: -(with-eval-after-load 'org-roam - - ;; ----------------------------- Org TODO Settings --------------------------- - - (setq org-todo-keywords '((sequence "TODO(t)" "PROJECT(p)" "DOING(i)" - "WAITING(w)" "VERIFY(v)" "STALLED(s)" - "DELEGATED(x)" "|" - "FAILED(f)" "DONE(d)" "CANCELLED(c)"))) - - (setq org-todo-keyword-faces - '(("TODO" . "green") - ("PROJECT" . "blue") - ("DOING" . "yellow") - ("WAITING" . "white") - ("VERIFY" . "orange") - ("STALLED" . "light blue") - ("DELEGATED" . "green") - ("FAILED" . "red") - ("DONE" . "dark grey") - ("CANCELLED" . "dark grey"))) - - (setq org-highest-priority ?A) - (setq org-lowest-priority ?D) - (setq org-default-priority ?D) - (setq org-priority-faces '((?A . (:foreground "Cyan" :weight bold)) - (?B . (:foreground "Yellow")) - (?C . (:foreground "Green")) - (?D . (:foreground "Grey")))) - - (setq org-enforce-todo-dependencies t) - (setq org-enforce-todo-checkbox-dependencies t) - (setq org-deadline-warning-days 7) ;; warn me w/in a week of deadlines - (setq org-log-done nil) ;; don't log when tasks was done - - ;; inherit parents properties (no schedules or deadlines) - (setq org-use-property-inheritance t) - - ;; ------------------ Org TODO Next/Previous Set Keybindings ----------------- - - (add-hook 'org-agenda-mode-hook (lambda () - (local-set-key (kbd "s-<right>") #'org-agenda-todo-nextset) - (local-set-key (kbd "s-<left>") #'org-agenda-todo-previousset))) - - ;; ------------------------------ Org Super Agenda ----------------------------- - - (use-package org-super-agenda - :config (org-super-agenda-mode)) - -;;;; ORG AGENDA VIEW DEFINITIONS - (defun cj/agenda-today-view() - "This agenda from all tasks that are scheduled or have a deadline." - (setq org-super-agenda-groups - '((:log t) ; Automatically named "Log" - (:name "SCHEDULED AND DUE" - :time-grid t - :deadline past - :deadline today - :scheduled past - :scheduled today) - (:habit t) - (:name "DUE SOON" - :deadline future) - (:name "LESS IMPORTANT" - :scheduled future - :order 100) - (:discard (:anything t))))) - - (defun cj/agenda-all-view() - "This agenda is built from all tasks." - (setq org-super-agenda-groups - '( - (:name "Ready To Go" - :todo "STAGED" - :todo "READY" - :order 5) - (:name "Due Today" - :deadline past - :deadline today - :order 2) - (:name "Empty Projects" - :todo "PROJECT" - :order 85) - (:name "Delegated" - :todo "DELEGATED" - :order 50) - (:name "Scheduled Later" - :scheduled future - :order 75) - (:name "Scheduled Today" - :scheduled today - :scheduled past - :order 4) - (:name "In Progress" - :todo "DOING" - :order 7) - (:name "High Priority" - :priority "A" - :order 10) - (:name "Waiting" - :todo "WAITING" - :order 60) - (:name "Upcoming" - :deadline future - :order 30) - (:name "Next Priority" - :priority "B" - :order 70) - (:name "Everything Else" - :anything t - :order 90)))) - - ;; ------------------------------ Add Agenda Time ------------------------------ - - (defun cj/add-agenda-time (s) - "Add an event with time S to appear underneath the line-at-point. -This allows a line to show in an agenda without being scheduled or a deadline." - (interactive "sTime: ") - (defvar cj/timeformat "%Y-%m-%d %a") - (org-end-of-line) - (save-excursion - (open-line 1) - (forward-line 1) - (insert (concat "<" (format-time-string cj/timeformat (current-time)) " " s ">" )))) - - (global-set-key (kbd "M-t") #'cj/add-agenda-time) - - ;; ---------------------------- Org Agenda Settings ---------------------------- - +(use-package org-agenda + :ensure nil ;; built-in + :after (org org-roam) + :config (setq org-agenda-prefix-format '((agenda . " %i %-25:c%?-12t% s") (timeline . " % s") - (todo . " %i %-25:c") - (tags . " %i %-12:c") - (search . " %i %-12:c"))) + (todo . " %i %-25:c") + (tags . " %i %-12:c") + (search . " %i %-12:c"))) (setq org-agenda-dim-blocked-tasks 'invisible) (setq org-agenda-skip-scheduled-if-done nil) - (setq org-agenda-skip-include-deadlines t) (setq org-agenda-remove-tags t) (setq org-agenda-compact-blocks t) - ;; ------------------------ Add Files To Org Agenda List ----------------------- - ;; finds files named 'todo.org' (case insensitive) and adds them to - ;; org-agenda-files list. + ;; display the agenda from the bottom + (add-to-list 'display-buffer-alist + '("\\*Org Agenda\\*" + (display-buffer-reuse-mode-window display-buffer-below-selected) + (dedicated . t) + (window-height . fit-window-to-buffer))) - (defun cj/add-files-to-org-agenda-files (directory) - "Recursively searches for files named 'todo.org', - Searches in DIRECTORY and adds them to org-project-files." - (interactive "D") - (setq org-agenda-files - (append (directory-files-recursively directory - "^[Tt][Oo][Dd][Oo]\\.[Oo][Rr][Gg]$" t) - org-agenda-files))) + ;; reset s-left/right each time org-agenda is enabled + (add-hook 'org-agenda-mode-hook (lambda () + (local-set-key (kbd "s-<right>") #'org-agenda-todo-nextset) + (local-set-key (kbd "s-<left>") + #'org-agenda-todo-previousset))) + ;; build org-agenda-list for the first time after emacs init completes. + (add-hook 'emacs-startup-hook #'cj/build-org-agenda-list)) - ;; NOTE: the following functions require org-roam functionality - (with-eval-after-load 'org-roam-config - ;; ---------------------------- Rebuild Org Agenda --------------------------- +;; ------------------------ Add Files To Org Agenda List ----------------------- +;; finds files named 'todo.org' (case insensitive) and adds them to +;; org-agenda-files list. - (defun cj/build-org-agenda-list () - "Rebuilds the org agenda list. -Begins with the inbox-file and schedule-file, then searches for org-roam -Projects and adds all todo.org files from code and project directories." - (interactive) - ;; reset org-agenda-files to inbox-file - (setq org-agenda-files (list inbox-file schedule-file)) - (let ((new-files - (append - (cj/org-roam-list-notes-by-tag "Project")))) - (dolist (file new-files) - (unless (member file org-agenda-files) - (setq org-agenda-files (cons file org-agenda-files))))) +(defun cj/add-files-to-org-agenda-files-list (directory) + "Search for files named \\='todo.org\\=' add them to org-project-files. +DIRECTORY is a string of the path to begin the search." + (interactive "D") + (setq org-agenda-files + (append (directory-files-recursively directory + "^[Tt][Oo][Dd][Oo]\\.[Oo][Rr][Gg]$" t) + org-agenda-files))) - (cj/add-files-to-org-agenda-files projects-dir) - (cj/add-files-to-org-agenda-files code-dir)) +;; ---------------------------- Rebuild Org Agenda --------------------------- +;; builds the org agenda list from all agenda targets. +;; agenda targets is the schedule, project todos, inbox, and org roam projects. - ;; build org-agenda-list for the first time once emacs init is complete. - (add-hook 'emacs-startup-hook 'cj/build-org-agenda-list) - - ;; ------------------------ Org Agenda Display Functions ----------------------- - - (defun cj/agenda-all-agenda-files-day () - "Display an \'org-agenda\' schedule with tasks covering today. +(defun cj/build-org-agenda-list () + "Rebuilds the org agenda list. +Begins with the inbox-file and schedule-file, then searches for org-roam +Projects and adds all todo.org files from code and project directories." + (interactive) + ;; reset org-agenda-files to inbox-file + (setq org-agenda-files (list inbox-file schedule-file)) + (let ((new-files + (append + (cj/org-roam-list-notes-by-tag "Project")))) + (dolist (file new-files) + (unless (member file org-agenda-files) + (setq org-agenda-files (cons file org-agenda-files))))) + + (cj/add-files-to-org-agenda-files-list projects-dir) + (cj/add-files-to-org-agenda-files-list code-dir)) + +;; ------------------------------ Agenda List All ------------------------------ +;; an agenda listing tasks from all available agenda targets. + +(defun cj/todo-list-all-agenda-files () + "Displays an \\='org-agenda\\=' todo list. The contents of the agenda will be built from org-project-files and org-roam files that have project in their filetag." - (interactive) - (cj/build-org-agenda-list) - (setq org-agenda-span 'day) - (cj/agenda-today-view) - (org-agenda "a" "a")) - (global-set-key (kbd "<f8>") #'cj/agenda-all-agenda-files-day) + (interactive) + (cj/build-org-agenda-list) + (org-agenda "a" "t")) +(global-set-key (kbd "C-<f8>") #'cj/todo-list-all-agenda-files) + +;; ------------------------- Agenda List Current Buffer ------------------------ +;; an agenda listing tasks from just the current buffer. + +(defun cj/todo-list-from-this-buffer () + "Displays an \\='org-agenda\\=' todo list built from the current buffer. +If the current buffer isn't an org buffer, inform the user." + (interactive) + (if (eq major-mode 'org-mode) + (let ((org-agenda-files (list buffer-file-name))) + (org-agenda "a" "t")) + (message (concat "Your org agenda request based on '" (buffer-name (current-buffer)) + "' failed because it's not an org buffer.")))) +(global-set-key (kbd "M-<f8>") #'cj/todo-list-from-this-buffer) + +;; -------------------------------- Main Agenda -------------------------------- +;; my custom agenda command from all available agenda targets. adapted from: +;; https://blog.aaronbieber.com/2016/09/24/an-agenda-for-life-with-org-mode.html + +(defvar cj/main-agenda-hipri-title "\nHIGH PRIORITY UNRESOLVED TASKS\n" + "String to announce the high priority section of the main agenda.") + +(defvar cj/main-agenda-schedule-title "\nSCHEDULE\n" + "String to announce the schedule section of the main agenda.") + +(defvar cj/main-agenda-tasks-title "\nPRIORITY B AND C\n" + "String to announce the schedule section of the main agenda.") + +(defun cj/org-skip-subtree-if-habit () + "Skip an agenda entry if it has a STYLE property equal to \"habit\"." + (let ((subtree-end (save-excursion (org-end-of-subtree t)))) + (if (string= (org-entry-get nil "STYLE") "habit") + subtree-end + nil))) + +(defun cj/org-skip-subtree-if-priority (priority) + "Skip an agenda subtree if it has a priority of PRIORITY. +PRIORITY may be one of the characters ?A, ?B, or ?C." + (let ((subtree-end (save-excursion (org-end-of-subtree t))) + (pri-value (* 1000 (- org-lowest-priority priority))) + (pri-current (org-get-priority (thing-at-point 'line t)))) + (if (= pri-value pri-current) + subtree-end + nil))) + +(defun cj/org-skip-subtree-if-keyword (keywords) + "Skip an agenda subtree if it has a TODO keyword in KEYWORDS. +KEYWORDS must be a list of strings." + (let ((subtree-end (save-excursion (org-end-of-subtree t)))) + (if (member (org-get-todo-state) keywords) + subtree-end + nil))) + +(setq org-agenda-custom-commands + '(("d" "Daily Agenda with Tasks" + ((tags "PRIORITY=\"A\"" + ((org-agenda-skip-function '(org-agenda-skip-entry-if 'todo 'done)) + (org-agenda-overriding-header cj/main-agenda-hipri-title))) + (agenda "" ((org-agenda-ndays 1) + (org-agenda-overriding-header cj/main-agenda-schedule-title))) + (alltodo "" + ((org-agenda-skip-function '(or (cj/org-skip-subtree-if-habit) + (cj/org-skip-subtree-if-priority ?A) + (cj/org-skip-subtree-if-priority ?D) + (cj/org-skip-subtree-if-keyword '("PROJECT")) + (org-agenda-skip-if nil '(scheduled deadline)))) + (org-agenda-overriding-header cj/main-agenda-tasks-title)))) + ((org-agenda-compact-blocks nil))))) + + + (defun cj/main-agenda-display () + "Display the main \'org-agenda\' display. +This uses all org-agenda targes and presents three sections: +- all unfinished priority A tasks +- the weekly schedule, including the habit consistency graph +- all priority B and C tasks" + (interactive) + (cj/build-org-agenda-list) + (org-agenda "a" "d")) +(global-set-key (kbd "<f8>") #'cj/main-agenda-display) +;; ------------------------- Add Timestamp To Org Entry ------------------------ +;; simply adds a timestamp to put the org entry on an agenda - (defun cj/agenda-all-agenda-files-week () - "Display an 'org-agenda' schedule with tasks covering this week. -The contents of the agenda will be built from org-project-files and org-roam -files that have project in their filetag." - (interactive) - (cj/build-org-agenda-list) - (setq org-agenda-span 'week) - (cj/agenda-today-view) - (org-agenda "a" "a")) - (global-set-key (kbd "s-<f8>") #'cj/agenda-all-agenda-files-week) - - (defun cj/todo-list-all-agenda-files () - "Displays an 'org-agenda' todo list. -The contents of the agenda will be built from org-project-files and org-roam -files that have project in their filetag." - (interactive) - (cj/build-org-agenda-list) - (cj/agenda-all-view) - (org-agenda "a" "t")) - (global-set-key (kbd "C-<f8>") #'cj/todo-list-all-agenda-files) - - (defun cj/todo-list-from-this-buffer () - "Displays an 'org-agenda' todo list built from the current buffer. - If the current buffer isn't an org buffer, inform the user." - (interactive) - (if (eq major-mode 'org-mode) - (let ((org-agenda-files (list buffer-file-name))) - (cj/agenda-all-view) - (org-agenda "a" "t")) - (message (concat "Your org agenda request based on '" (buffer-name (current-buffer)) - "' failed because it's not an org buffer.")))) - (global-set-key (kbd "M-<f8>") #'cj/todo-list-from-this-buffer) - - ;; --------------------------- Notifications / Alerts -------------------------- - ;; send libnotify notifications about agenda items - - (use-package alert - :defer .5 - :config - (setq alert-fade-time 10) ;; secs to vanish alert - (setq alert-default-style 'libnotify)) ;; work with dunst - - (use-package org-alert - :defer .5 - :bind - ("C-c A" . org-alert-check) - :config - (setq alert-default-style 'libnotify) ;; work with dunst - (setq org-alert-interval 300) ;; seconds checks agenda is checked (300 = 5 mins) - (setq org-alert-notify-cutoff 5) ;; minutes before a deadline to send alert - (setq org-alert-notify-after-event-cutoff 10) ;; mins post deadline to stop alerts - (setq org-alert-notification-title "Reminder") - (org-alert-enable)) - - - ) ;; end with-eval-after-load 'org-roam-config - ) ;; end with-eval-after-load 'org-roam +(defun cj/add-timestamp-to-org-entry (s) + "Add an event with time S to appear underneath the line-at-point. +This allows a line to show in an agenda without being scheduled or a deadline." + (interactive "sTime: ") + (defvar cj/timeformat "%Y-%m-%d %a") + (org-end-of-line) + (save-excursion + (open-line 1) + (forward-line 1) + (insert (concat "<" (format-time-string cj/timeformat (current-time)) " " s ">" )))) +(global-set-key (kbd "M-t") #'cj/add-timestamp-to-org-entry) + +;; --------------------------- Notifications / Alerts -------------------------- +;; send libnotify notifications about agenda items + +(use-package alert + :defer .5 + :after org-agenda + :config + (setq alert-fade-time 10) ;; secs to vanish alert + (setq alert-default-style 'libnotify)) ;; work with dunst + +(use-package org-alert + :defer .5 + :after alert + :bind + ("C-c A" . org-alert-check) + :config + (setq alert-default-style 'libnotify) ;; work with dunst + (setq org-alert-interval 180) ;; seconds between agenda checks (180 = 3 mins) + (setq org-alert-notify-cutoff 5) ;; minutes before a deadline to send alert + (setq org-alert-notify-after-event-cutoff 10) ;; mins post deadline to stop alerts + (setq org-alert-notification-title "Reminder") + (org-alert-enable)) (provide 'org-agenda-config) ;;; org-agenda-config.el ends here diff --git a/modules/org-capture-config.el b/modules/org-capture-config.el index 8feab2bf..4fa7af41 100644 --- a/modules/org-capture-config.el +++ b/modules/org-capture-config.el @@ -78,31 +78,57 @@ Intended to be called within an org capture template." ;; ORG-CAPTURE TEMPLATES (setq org-protocol-default-template-key "L") (setq org-capture-templates - '( + '(("t" "Task" entry (file+headline inbox-file "Inbox") + "* TODO %?" :prepend t) + ("e" "Event" entry (file+headline schedule-file "Scheduled Events") "* %?\nWHEN: %^t" :prepend t) ("E" "Epub Text" entry (file+headline inbox-file "Inbox") - "* %?\n#+BEGIN_QUOTE\n %i\n#+END_QUOTE\nSource: [[%:link][%(buffer-name (org-capture-get :original-buffer))]]\nCaptured On: %U" :prepend t) + "* %? +#+BEGIN_QUOTE\n %i\n#+END_QUOTE +Source: [[%:link][%(buffer-name (org-capture-get :original-buffer))]] +Captured On: %U" :prepend t) ("P" "PDF Text" entry (file+headline inbox-file "Inbox") - "* %?\n#+BEGIN_QUOTE\n %(org-capture-pdf-active-region)\n#+END_QUOTE\nSource:[[%L][%(buffer-name (org-capture-get :original-buffer))]]\nCaptured On: %U" :prepend t) + "* %? +#+BEGIN_QUOTE\n%(org-capture-pdf-active-region)\n#+END_QUOTE +Source:[[%L][%(buffer-name (org-capture-get :original-buffer))]] +Captured On: %U" :prepend t) ("p" "Link with Selection" entry (file+headline inbox-file "Inbox") - "* TODO %?\n#+BEGIN_QUOTE\n%i\n#+END_QUOTE\n[[%:link][%:description]]\nCaptured On: %U" :prepend t) + "* %?%:description +#+BEGIN_QUOTE\n%i\n#+END_QUOTE +[[%:link][%:description]] +Captured On: %U\n" :prepend t) ("L" "Link" entry (file+headline inbox-file "Inbox") - "* TODO %?\n[[%:link][%:description]]\nCaptured On: %U" :prepend t) + "* %?%:description +[[%:link][%:description]]\nCaptured On: %U" :prepend t :immediate-finish t) ("m" "Mu4e Email" entry (file+headline inbox-file "Inbox") - "* TODO %?%(if (string= \"%i\" \"\") \"\" \"\n#+BEGIN_QUOTE\n%i\n#+END_QUOTE\")\n[[%:link][%:description]]\nCaptured On: %U" + "* TODO %? +%(if (string= \"%i\" \"\") \"\" \"\n#+BEGIN_QUOTE\n%i\n#+END_QUOTE\") +[[%:link][%:description]] +Captured On: %U" :prepend t) - ("w" "Web Page Clipper" plain - (function cj/org-webpage-clipper) + ("g" "Grocery List Item" item + (file+headline inbox-file "Grocery List") "%?") + + ("s" "Shopping List Entry" entry + (file+headline inbox-file "Shopping List") "* %?") + + ("w" "Web Page Clipper" plain + (function cj/org-webpage-clipper) "* %a\nArticle Link: %L\nCaptured On: %U\n\n" :immediate-finish t))) ) ;; end with-eval-after-load 'org +;; ---------------------------- Simple Task Capture ---------------------------- +;; the simplest way to capture a task. Also a simple way to write this function. + +(define-key global-map (kbd "C-S-t") (kbd "C-c c t")) + (provide 'org-capture-config) ;;; org-capture-config.el ends here. diff --git a/modules/org-config.el b/modules/org-config.el index 0094cc9d..f084a8c0 100644 --- a/modules/org-config.el +++ b/modules/org-config.el @@ -18,25 +18,88 @@ ;;; Code: -;;;; --------------------------- Constants --------------------------- +;; --------------------------------- Constants --------------------------------- ;; note: some constants used here are defined in init.el (defvar org-archive-location (concat sync-dir "/archives/archive.org::datetree/")) ;; location of archive file (defvar org-project-files (list schedule-file)) -;; ---------------------------- APT Sorting Function --------------------------- +;; ---------------------------- Org General Settings --------------------------- -(defun cj/org-reorder-list-apt () - "Sort the org header by three criteria: alpha, pri, then todo." - (interactive) - (save-excursion - (ignore-errors - (progn - (org-sort-entries t ?a) - (org-sort-entries t ?p) - (org-sort-entries t ?t) - (org-cycle) - (org-cycle))))) +(defun cj/org-general-settings () + "All general \='org-mode\=' settings are grouped and set in this function." + + ;; Unbind org-cycle-agenda-files keys for use elsewhere + (unbind-key "C-'" org-mode-map) + (unbind-key "C-," org-mode-map) + + ;; ORG-MODULES + ;; enable recognition of org-protocol:// as a parameter + ;; add org-habits + (require 'org-protocol) + (setq org-modules '(org-protocol ol-eww ol-w3m ol-info org-habit)) + + ;; GENERAL + (setq org-startup-folded t) ;; all org files should start in the folded state + (setq org-cycle-open-archived-trees t) ;; re-enable opening headings with archive tags with TAB + (setq org-outline-path-complete-in-steps nil) + (setq org-return-follows-link t) ;; hit return to follow an org-link + (setq org-list-allow-alphabetical t) ;; allow alpha ordered lists (i.e., a), A), a., etc.) + + ;; INDENTATION + (setq org-startup-indented t) ;; load org files indented + (setq org-adapt-indentation t) ;; adapt indentation to outline node level + (setq org-indent-indentation-per-level 2) ;; indent two character-widths per level + + ;; INLINE IMAGES + (setq org-startup-with-inline-images t) ;; preview images by default + (setq org-image-actual-width '(500)) ;; keep image sizes in check + + (setq org-bookmark-names-plist nil) ;; don't set org-capture bookmarks + + ;; force pdfs exported from org to open in emacs + (add-to-list 'org-file-apps '("\\.pdf\\'" . emacs))) + +;; ----------------------------- Org TODO Settings --------------------------- + +(defun cj/org-todo-settings () + "All org-todo related settings are grouped and set in this function." + + ;; logging task creation, task start, and task resolved states + (setq org-todo-keywords '((sequence "TODO(t!)" "PROJECT(p)" "DOING(i!)" + "WAITING(w)" "VERIFY(v)" "STALLED(s)" + "DELEGATED(x)" "|" + "FAILED(f!)" "DONE(d!)" "CANCELLED(c!)"))) + + (setq org-todo-keyword-faces + '(("TODO" . "green") + ("PROJECT" . "blue") + ("DOING" . "yellow") + ("WAITING" . "white") + ("VERIFY" . "orange") + ("STALLED" . "light blue") + ("DELEGATED" . "green") + ("FAILED" . "red") + ("DONE" . "dark grey") + ("CANCELLED" . "dark grey"))) + + (setq org-highest-priority ?A) + (setq org-lowest-priority ?D) + (setq org-default-priority ?D) + (setq org-priority-faces '((?A . (:foreground "Cyan" :weight bold)) + (?B . (:foreground "Yellow")) + (?C . (:foreground "Green")) + (?D . (:foreground "Grey")))) + + (setq org-enforce-todo-dependencies t) + (setq org-enforce-todo-checkbox-dependencies t) + (setq org-deadline-warning-days 7) ;; warn me w/in a week of deadlines + (setq org-treat-insert-todo-heading-as-state-change t) ;; log task creation + (setq org-log-into-drawer t) ;; log into the drawer + (setq org-habit-graph-column 75) ;; allow space for task name + + ;; inherit parents properties (sadly not schedules or deadlines) + (setq org-use-property-inheritance t)) ;; ---------------------------------- Org Mode --------------------------------- @@ -57,7 +120,6 @@ ("C-\\" . org-match-sparse-tree) ("C-c t" . org-set-tags-command) ("C-c l" . org-store-link) - ("C-c r" . cj/org-reorder-list-apt) ("C-c C-l" . org-insert-link) ("s-<up>" . org-priority-up) ("s-<down>" . org-priority-down) @@ -112,40 +174,38 @@ (org-mode . (lambda () (interactive) (company-mode -1))) ;; no company-mode in org :config - ;; Unbind org-cycle-agenda-files keys for use elsewhere - (unbind-key "C-'" org-mode-map) - (unbind-key "C-," org-mode-map) + (cj/org-general-settings) + (cj/org-todo-settings)) - ;; ORG-PROTOCOL - ;; enable recognition of org-protocol:// as a parameter - (require 'org-protocol) - (setq org-modules '(org-protocol ol-eww ol-w3m ol-info)) +;; ------------------------------- Org-Checklist ------------------------------- +;; needed for org-habits to reset checklists once task is complete +;; this was a part of org-contrib which was deprecated - ;; GENERAL - (setq org-startup-folded t) ;; all org files should start in the folded state - (setq org-cycle-open-archived-trees t) ;; re-enable opening headings with archive tags with TAB - (setq org-outline-path-complete-in-steps nil) - (setq org-return-follows-link t) ;; hit return to follow an org-link - (setq org-list-allow-alphabetical t) ;; allow alpha ordered lists (i.e., a), A), a., etc.) +(use-package org-checklist + :ensure nil ;; in custom folder + :after org + :load-path "custom/org-checklist.el") - ;; INDENTATION - (setq org-startup-indented t) ;; load org files indented - (setq org-adapt-indentation t) ;; adapt indentation to outline node level - (setq org-indent-indentation-per-level 2) ;; indent two character-widths per level +;; -------------------------- Org Link To Current File ------------------------- +;; get a link to the file the current buffer is associated with. - ;; INLINE IMAGES - (setq org-startup-with-inline-images t) ;; preview images by default - (setq org-image-actual-width '(500)) ;; keep image sizes in check - - (setq org-bookmark-names-plist nil) ;; don't set org-capture bookmarks - - ;; force pdfs exported from org to open in emacs - (add-to-list 'org-file-apps '("\\.pdf\\'" . emacs))) +(defun cj/org-link-to-current-buffer-file () + "Create an Org mode link to the current file and copy it to the clipboard. +The link is formatted as [[file:<file-path>][<file-name>]], +where <file-path> is the full path to the current file and <file-name> +is the name of the current file without any directory information. -;; https://www.reddit.com/r/orgmode/comments/n56fcv/important_the_contrib_directory_now_lives_outside/ -;; (use-package org-contrib -;; :after org) +If the current buffer is not associated with a file, the function will throw an +error." + (interactive) + (if (buffer-file-name) + (let* ((filename (buffer-file-name)) + (description (file-name-nondirectory filename)) + (link (format "[[file:%s][%s]]" filename description))) + (kill-new link) + (message "Copied Org link to current file to clipboard: %s" link)) + (user-error "Buffer isn't associated with a file, so no link sent to clipboard"))) (provide 'org-config) ;;; org-config.el ends here diff --git a/modules/org-roam-config.el b/modules/org-roam-config.el index c9a5bad1..d6c437b2 100644 --- a/modules/org-roam-config.el +++ b/modules/org-roam-config.el @@ -6,42 +6,48 @@ ;;; Code: - ;; ---------------------------------- Org Roam --------------------------------- (use-package org-roam :after org :defer .5 :custom - (org-roam-directory "~/sync/org/roam/") + (org-roam-directory roam-dir) (org-roam-dailies-directory "journal/") (org-roam-completion-everywhere t) (org-roam-dailies-capture-templates '(("d" "default" entry "* %<%I:%M:%S %p %Z> %?" - :if-new (file+head "%<%Y-%m-%d>.org" "#+FILETAGS: Journal\n#+TITLE: %<%Y-%m-%d>")))) + :if-new (file+head "%<%Y-%m-%d>.org" "#+FILETAGS: Journal +#+TITLE: %<%Y-%m-%d>")))) (org-roam-capture-templates - '(("d" "default" plain - "%?" + '(("d" "default" plain "%?" :if-new (file+head "%<%Y%m%d%H%M%S>-${slug}.org" "#+TITLE: ${title}\n") :unnarrowed t) - ("v" "v2mom" plain (file "~/sync/org/roam/templates/v2mom.org") + ("v" "v2mom" plain + (function (lambda () (concat roam-dir "templates/v2mom.org"))) :if-new (file+head "%<%Y%m%d%H%M%S>-${slug}.org" "#+TITLE: ${title}\n") :unnarrowed t) - ("r" "recipe" plain (file "~/sync/org/roam/templates/recipe.org") - :if-new (file+head "%<%Y%m%d%H%M%S>-${slug}.org" "#+TITLE: ${title}\n#+CATEGORY: ${title}\n#+FILETAGS: Recipe") + ("r" "recipe" plain + (function (lambda () (concat roam-dir "templates/recipe.org"))) + :if-new (file+head "%<%Y%m%d%H%M%S>-${slug}.org" "#+TITLE: ${title} + #+CATEGORY: ${title}\n#+FILETAGS: Recipe") :unnarrowed t) - ("p" "project" plain (file "~/sync/org/roam/templates/project.org") - :if-new (file+head "%<%Y%m%d%H%M%S>-${slug}.org" "#+TITLE: ${title}\n#+CATEGORY: ${title}\n#+FILETAGS: Project") + ("p" "project" plain + (function (lambda () (concat roam-dir "templates/project.org"))) + :if-new (file+head "%<%Y%m%d%H%M%S>-${slug}.org" "#+TITLE: ${title} + #+CATEGORY: ${title}\n#+FILETAGS: Project") :unnarrowed t) - ("t" "topic" plain (file "~/sync/org/roam/templates/topic.org") - :if-new (file+head "%<%Y%m%d%H%M%S>-${slug}.org" "#+TITLE: ${title}\n#+CATEGORY: ${title}\n#+FILETAGS: Topic") + ("t" "topic" plain + (function (lambda () (concat roam-dir "templates/topic.org"))) + :if-new (file+head "%<%Y%m%d%H%M%S>-${slug}.org" "#+TITLE: ${title} + #+CATEGORY: ${title}\n#+FILETAGS: Topic") :unnarrowed t))) :bind (("C-c n ?" . org-roam-hydra/body) ("C-c n l" . org-roam-buffer-toggle) ("C-c n f" . org-roam-node-find) - ("C-c n p" . cj/org-roam-find-project) - ("C-c n r" . cj/org-roam-find-recipe) - ("C-c n t" . cj/org-roam-find-topic) + ("C-c n p" . cj/org-roam-find-node-project) + ("C-c n r" . cj/org-roam-find-node-recipe) + ("C-c n t" . cj/org-roam-find-node-topic) ("C-c n i" . org-roam-node-insert) :map org-mode-map ("C-M-i" . completion-at-point) @@ -59,9 +65,9 @@ ;; move closed tasks to today's journal when marked done (add-to-list 'org-after-todo-state-change-hook - (lambda () - (when (equal org-state "DONE") - (cj/org-roam-copy-todo-to-today)))) + (lambda () + (when (equal org-state "DONE") + (cj/org-roam-copy-todo-to-today)))) (require 'org-roam-dailies) ;; Ensures the keymap is available (org-roam-db-autosync-mode)) @@ -70,34 +76,40 @@ (defun cj/org-roam-node-insert-immediate (arg &rest args) "Create new node and insert its link immediately. -The prefix ARG . -ARGS represents the node name to link." +This is mainly a wrapper around org-roam-node-insert to achieve immediate finish +to the capture. The prefix ARG and ARGS are the filter function and the rest of +the arguments that org-roam-node-insert expects." (interactive "P") (let ((args (cons arg args)) - (org-roam-capture-templates (list (append (car org-roam-capture-templates) - '(:immediate-finish t))))) - (apply #'org-roam-node-insert args))) + (org-roam-capture-templates (list (append (car org-roam-capture-templates) + '(:immediate-finish t))))) + (apply #'org-roam-node-insert args))) (global-set-key (kbd "C-c n I") 'cj/org-roam-node-insert-immediate) ;; ------------------------- Tag Listing And Filtering ------------------------- (defun cj/org-roam-filter-by-tag (tag-name) (lambda (node) - (member tag-name (org-roam-node-tags node)))) + (member tag-name (org-roam-node-tags node)))) (defun cj/org-roam-list-notes-by-tag (tag-name) (mapcar #'org-roam-node-file - (seq-filter - (cj/org-roam-filter-by-tag tag-name) - (org-roam-node-list)))) + (seq-filter + (cj/org-roam-filter-by-tag tag-name) + (org-roam-node-list)))) ;; -------------------------- Org Roam Find Functions -------------------------- (defun cj/org-roam-find-node (tag template-key template-file) - "List all node of type \='TAG\=' in completing read for selection or creation." + "List all nodes of type \='TAG\=' in completing read for selection or creation. +Interactively find or create an Org-roam node with a given \='TAG\='. Newly +created nodes are added to the agenda and follow a template defined by +\='TEMPLATE-KEY\=' and \='TEMPLATE-FILE\='." + (interactive) ;; Add the project file to the agenda after capture is finished - (add-hook 'org-capture-after-finalize-hook #'cj/org-roam-add-node-to-agenda-files-finalize-hook) + (add-hook 'org-capture-after-finalize-hook + #'cj/org-roam-add-node-to-agenda-files-finalize-hook) ;; Select a project file to open, creating it if necessary (org-roam-node-find @@ -107,86 +119,86 @@ ARGS represents the node name to link." nil :templates `((,template-key ,tag plain (file ,template-file) - :if-new (file+head "%<%Y%m%d%H%M%S>-${slug}.org" ,(concat "#+TITLE: ${title}\n#+CATEGORY: ${title}\n#+FILETAGS: " tag)) - :unnarrowed t)))) + :if-new (file+head "%<%Y%m%d%H%M%S>-${slug}.org" + ,(concat "#+TITLE: ${title} +#+CATEGORY: ${title}\n#+FILETAGS: " tag)) + :unnarrowed t)))) -(defun cj/org-roam-find-topic () - "List all node of type \=`topic\=` in completing read for selection or creation." +(defun cj/org-roam-find-node-topic () + "List nodes of type \=`topic\=` in completing read for selection or creation." (interactive) - (cj/org-roam-find-node "Topic" "t" "~/sync/org/roam/templates/topic.org")) + (cj/org-roam-find-node "Topic" "t" (concat roam-dir "templates/topic.org"))) -(defun cj/org-roam-find-recipe () - "List all node of type \=`recipe\=` in completing read for selection or creation." +(defun cj/org-roam-find-node-recipe () + "List nodes of type \=`recipe\=` in completing read for selection or creation." (interactive) - (cj/org-roam-find-node "Recipe" "r" "~/sync/org/roam/templates/recipe.org")) + (cj/org-roam-find-node "Recipe" "r" (concat roam-dir "templates/recipe.org"))) + +(defun cj/org-roam-find-node-project () + "List nodes of type \='project\=' in completing read for selection or creation." -(defun cj/org-roam-find-project () - "List all node of type \='project\=' in completing read for selection or creation." (interactive) - (cj/org-roam-find-node "Project" "p" "~/sync/org/roam/templates/project.org")) + (cj/org-roam-find-node "Project" "p" (concat roam-dir "templates/project.org"))) ;; ---------------------- Org Capture After Finalize Hook ---------------------- (defun cj/org-roam-add-node-to-agenda-files-finalize-hook () "Add the captured project file to \='org-agenda-files\='." ;; Remove the hook since it was added temporarily - (remove-hook 'org-capture-after-finalize-hook #'cj/org-roam-add-node-to-agenda-files-finalize-hook) + (remove-hook 'org-capture-after-finalize-hook + #'cj/org-roam-add-node-to-agenda-files-finalize-hook) + ;; Add project file to the agenda list if the capture was confirmed (unless org-note-abort - (with-current-buffer (org-capture-get :buffer) - (add-to-list 'org-agenda-files (buffer-file-name))))) - -;; ------------------------------- Capture Inbox ------------------------------- - -(defun cj/org-roam-capture-inbox () - (interactive) - (org-roam-capture- :node (org-roam-node-create) - :templates '(("i" "inbox" plain "** %?" - :if-new (file+head+olp "~/sync/org/roam/inbox.org" - "#+TITLE: Inbox\n#+CATEGORY: Inbox\n#+FILETAGS: Project" - ("Inbox")))))) -(global-set-key (kbd "C-t") #'cj/org-roam-capture-inbox) + (with-current-buffer (org-capture-get :buffer) + (add-to-list 'org-agenda-files (buffer-file-name))))) ;; -------------------------------- Capture Task ------------------------------- -(defun cj/org-roam-capture-task () +(defun cj/org-roam-capture-task-into-project () + "Create a new project and add a task immediately to it." (interactive) ;; Add the project file to the agenda after capture is finished - (add-hook 'org-capture-after-finalize-hook #'cj/org-roam-add-node-to-agenda-files-finalize-hook) + (add-hook 'org-capture-after-finalize-hook + #'cj/org-roam-add-node-to-agenda-files-finalize-hook) ;; Capture the new task, creating the project file if necessary - (org-roam-capture- :node (org-roam-node-read - nil - (cj/org-roam-filter-by-tag "Project")) - :templates '(("p" "project" plain "** TODO %?" - :if-new (file+head+olp "%<%Y%m%d%H%M%S>-${slug}.org" - "#+TITLE: ${title}\n#+CATEGORY: ${title}\n#+FILETAGS: Project" - ("${title}")))))) -(global-set-key (kbd "C-c n t") #'cj/org-roam-capture-task) + (org-roam-capture- + :node (org-roam-node-read + nil + (cj/org-roam-filter-by-tag "Project")) + :templates '(("p" "project" plain "** TODO %?" + :if-new (file+head+olp "%<%Y%m%d%H%M%S>-${slug}.org" + "#+TITLE: ${title} +#+CATEGORY: ${title} +#+FILETAGS: Project" + ("${title}")))))) +(global-set-key (kbd "C-c n t") #'cj/org-roam-capture-task-into-project) ;; ------------------------ Org Roam Copy Done To Daily ------------------------ (defun cj/org-roam-copy-todo-to-today () + "Copy completed tasks to today's daily org-roam node." (interactive) (let ((org-refile-keep t) ;; Set this to nil to delete the original! - (org-roam-dailies-capture-templates - '(("t" "tasks" entry "%?" - :if-new (file+head+olp "%<%Y-%m-%d>.org" "#+FILETAGS: Journal\n#+TITLE: %<%Y-%m-%d>\n" ("Completed Tasks"))))) - (org-after-refile-insert-hook #'save-buffer) - today-file - pos) - (save-window-excursion - (org-roam-dailies--capture (current-time) t) - (setq today-file (buffer-file-name)) - (setq pos (point))) - - ;; Only refile if the target file is different than the current file - (unless (equal (file-truename today-file) - (file-truename (buffer-file-name))) - (org-refile nil nil (list "Completed Tasks" today-file nil pos))))) - - + (org-roam-dailies-capture-templates + '(("t" "tasks" entry "%?" + :if-new (file+head+olp "%<%Y-%m-%d>.org" + "#+FILETAGS: Journal +#+TITLE: %<%Y-%m-%d>\n" ("Completed Tasks"))))) + (org-after-refile-insert-hook #'save-buffer) + today-file + pos) + (save-window-excursion + (org-roam-dailies--capture (current-time) t) + (setq today-file (buffer-file-name)) + (setq pos (point))) + + ;; Only refile if the target file is different than the current file + (unless (equal (file-truename today-file) + (file-truename (buffer-file-name))) + (org-refile nil nil (list "Completed Tasks" today-file nil pos))))) (provide 'org-roam-config) ;;; org-roam-config.el ends here. diff --git a/modules/prog-general.el b/modules/prog-general.el index b6b58494..2338564f 100644 --- a/modules/prog-general.el +++ b/modules/prog-general.el @@ -141,6 +141,28 @@ If none exists, it opens magit-status." :bind ("C-c s i" . ivy-yasnippet)) +;; ----------------------- Export Org To Markdown On Save ---------------------- +;; if the file has the proper header, saving an org file will also export to +;; markdown with a timestamp. The header is this: +;; # -*- org-auto-export-to-md: t; -*- +;; #+DATE: +;; and is available as the org-export-md snippet + +(defvar org-auto-export-to-md nil) + +(defun cj/export-org-to-md-on-save () + "Export the current org file to Markdown format on save." + (when (and (eq major-mode 'org-mode) + org-auto-export-to-md) + (save-excursion + (goto-char (point-min)) + (search-forward "#+DATE:") + (kill-line) + (insert (format-time-string " %Y-%m-%d %H:%M")) + (org-md-export-to-markdown)))) + +(add-hook 'after-save-hook 'cj/export-org-to-md-on-save) + ;; --------------------- Display Color On Color Declaration -------------------- ;; display the actual color as highlight to color hex code diff --git a/modules/prog-lisp.el b/modules/prog-lisp.el index 618108bd..59eb122b 100644 --- a/modules/prog-lisp.el +++ b/modules/prog-lisp.el @@ -31,15 +31,17 @@ ;; $ rlwrap sbcl ;;; Code: +(require 'ert) ;; -------------------------------- Elisp Setup -------------------------------- ;; run this on editing an elisp file (defun cj/elisp-setup () "My default code preferences for emacs-lisp." - (setq-default tab-width 4) ;; set the tab width to 4 spaces - (setq-default indent-tabs-mode -1) ;; disable tab characters - (setq-default fill-column 80)) + (setq-default tab-width 4) ;; set the tab width to 4 spaces + (setq-default indent-tabs-mode -1) ;; disable tab characters + (setq-default fill-column 80) ;; default column for gnu projects + (display-fill-column-indicator-mode)) ;; show where the 80th column is (add-hook 'emacs-lisp-mode-hook 'cj/elisp-setup) ;; ------------------------------ Emacs Lisp REPL ------------------------------ @@ -85,7 +87,7 @@ (defun cj/eval-and-run-all-tests-in-buffer () - "Delete loaded tests, evaluate current buffer. and run all loaded ERT tests." + "Delete any loaded tests, evaluate current buffer, and run loaded ERT tests." (interactive) (ert-delete-all-tests) (eval-buffer) diff --git a/modules/show-kill-ring.el b/modules/show-kill-ring.el index a1f3a637..dbe7c934 100644 --- a/modules/show-kill-ring.el +++ b/modules/show-kill-ring.el @@ -63,12 +63,11 @@ This makes it easy to figure out which prefix to pass to yank." ;; show it (goto-char (point-min)) (setq buffer-read-only t) - (set-buffer-modified-p nil) - - ;; it's better to leave the point in it's buffer - ;; so user can C-u (Item#) C-y in place. - ;; (pop-to-buffer buf) - )) + (set-buffer-modified-p nil) + ;; display-buffer rather than pop-to-buffer + ;; easier for user to C-u (item#) C-y + ;; while the point is where they want to yank + (display-buffer buf))) (defun show-kill-insert-item (item) "Insert an ITEM from the kill ring into the current buffer. diff --git a/modules/system-utils.el b/modules/system-utils.el index 0592f928..0ec287b9 100644 --- a/modules/system-utils.el +++ b/modules/system-utils.el @@ -25,7 +25,10 @@ ;; 'cj/buffer-bury-alive-list' via 'C-u C-x k' ;; BUFFER BURY ALIVE LIST -(defvar cj/buffer-bury-alive-list '("*dashboard*" "*scratch*" "*Messages*") +(defvar cj/buffer-bury-alive-list '("*dashboard*" + "*scratch*" + "*Messages*" + "*ChatGPT*") "Buffers that shouldn't be killed, but buried instead.") ;; KILL BUFFER AND WINDOW diff --git a/modules/test-code.el b/modules/test-code.el index 6c4fadcd..d9759e6e 100644 --- a/modules/test-code.el +++ b/modules/test-code.el @@ -34,13 +34,13 @@ (use-package easy-hugo :defer .5 :init - (setq easy-hugo-basedir "~/code/cjennings.net/") + (setq easy-hugo-basedir "~/code/cjennings-net/") (setq easy-hugo-url "https://cjennings.net") (setq easy-hugo-sshdomain "cjennings.net") (setq easy-hugo-root "/var/www/cjennings/") (setq easy-hugo-previewtime "300") (setq easy-hugo-postdir "content") - (setq easy-hugo-server-flags "-D") + (setq easy-hugo-server-flags "-D --noHTTPCache --disableFastRender") (setq easy-hugo-default-ext ".md") :bind ("C-c H" . easy-hugo) :config @@ -113,6 +113,7 @@ otherwise use the default location in `cj/recording-location'." (use-package wttrin :defer .5 :load-path ("~/code/emacs-wttrin") + :ensure nil ;; local package :preface ;; dependency for wttrin (use-package xterm-color diff --git a/modules/ui-theme.el b/modules/ui-theme.el index 64fa739b..8d83ac50 100644 --- a/modules/ui-theme.el +++ b/modules/ui-theme.el @@ -45,13 +45,15 @@ Unloads any other applied themes before applying the chosen theme." ;; persistence utility functions used by switch themes. (defvar theme-file (concat sync-dir "emacs-theme.persist") - "The location of the file to persist the theme name.") + "The location of the file to persist the theme name. +If you want your theme change to persist across instances, put this in a +directory that is sync'd across machines with this configuration.") -(defvar fallback-theme-name "wombat" +(defvar fallback-theme-name "modus-vivendi" "The name of the theme to fallback on. This is used then there's no file, or the theme name doesn't match -any of the installed themes. If theme name is 'nil', there will be -no theme.") +any of the installed themes. This should be a built-in theme. If theme name is +'nil', there will be no theme.") (defun cj/read-file-contents (filename) "Read FILENAME and return its content as a string. @@ -97,14 +99,14 @@ loading the file name, the fallback-theme-name is applied and saved." ;; if theme-name is nil, unload all themes and load fallback theme (if (or (string= theme-name "nil") (not theme-name)) (progn - (mapcar #'disable-theme custom-enabled-themes) - (cj/load-fallback-theme "Theme file not found or theme name in it is nil.")) + (mapcar #'disable-theme custom-enabled-themes) + (cj/load-fallback-theme "Theme file not found or theme name in it is nil.")) ;; apply theme name or if error, load fallback theme (condition-case err (load-theme (intern theme-name) t) (error - (cj/load-fallback-theme (concat "Error loading " theme-name - "."))))))) + (cj/load-fallback-theme (concat "Error loading " theme-name + "."))))))) (cj/load-theme-from-file) diff --git a/modules/vc-config.el b/modules/vc-config.el index a9b72507..769825a8 100644 --- a/modules/vc-config.el +++ b/modules/vc-config.el @@ -28,7 +28,14 @@ (setf vc-handled-backends nil) ;; magit is the only vc interface I use (setq magit-bury-buffer-function 'magit-restore-window-configuration) (setq git-commit-major-mode 'org-mode) ;; edit commit messages in org-mode - (setq magit-display-buffer-function 'magit-display-buffer-fullframe-status-topleft-v1)) + (setq magit-display-buffer-function + 'magit-display-buffer-fullframe-status-topleft-v1) + + ;; CLONING + (setq magit-clone-default-directory code-dir) ;; cloned repositories go here by default + (setq magit-clone-set-remote-head t) ;; do as git does for remote heads + (setq magit-clone-set-remote.pushDefault 'ask) ;; ask if origin is default + ) ;; end use-package magit ;; --------------------------------- Git Gutter -------------------------------- ;; mark changed lines since last commit in the margin |
