summaryrefslogtreecommitdiff
path: root/modules
diff options
context:
space:
mode:
authorCraig Jennings <c@cjennings.net>2025-08-30 12:13:52 -0500
committerCraig Jennings <c@cjennings.net>2025-08-30 12:13:52 -0500
commit088e2b3f14f0ea02038e20dccbb62e05d4eec9b2 (patch)
treec2b9654f45741553be4c8b644d6c9f5a43f25b35 /modules
parent6be403ded18185bd26af38a9db734a970ca61537 (diff)
downloaddotemacs-088e2b3f14f0ea02038e20dccbb62e05d4eec9b2.tar.gz
dotemacs-088e2b3f14f0ea02038e20dccbb62e05d4eec9b2.zip
email, ai, and miscellaneous
refactor setup-email script - Enable "set -euo pipefail" for safer execution - Quote all variable references in test conditions - Update script header with usage notes and email setup steps email and org-msg changes - Configure org-msg with inline CSS, greeting, images, citations, and signature - Enable org-msg-mode in all mu4e compose buffers - Advise mu4e-compose-reply and mu4e-compose-wide-reply to use org-msg-edit-mode - Move no-auto-fill hook into mu4e-compose-mode-hook - Disable mu4e-compose-format-flowed and set mu4e-html2text-command - Update gnus-blocked-images comment and remove default signature-file setting - remove org-contact configurations ai changes - historian directive added - added all new directives to menu - changed default directive to default-directive! misc changes - org complains when tab-widths aren't at 8 - refactor and improve delete blank lines region or buffer - change name of add-header function to be more specific - updated tasks - updated abbrevs - documentation for local-arch-wiki-search
Diffstat (limited to 'modules')
-rw-r--r--modules/ai-config.el19
-rw-r--r--modules/custom-functions.el36
-rw-r--r--modules/help-utils.el5
-rw-r--r--modules/mail-config.el135
-rw-r--r--modules/org-config.el1
-rw-r--r--modules/org-contacts-config.el27
6 files changed, 102 insertions, 121 deletions
diff --git a/modules/ai-config.el b/modules/ai-config.el
index 6f0462da..0db11009 100644
--- a/modules/ai-config.el
+++ b/modules/ai-config.el
@@ -64,7 +64,11 @@
"I want you to act as an email writing assistant. I will provide you some direction on what the
email should consist of, the tone of the email, and my guess as to the DISC profile of the email recipient. You will use
the DISC profile information to guide the tone and wording of the email. However, always lean towards simple,
-straightforward, and clear language with little ambiguity. Ask questions to make any part of the email clearer if needed.")
+straightforward, and clear language with little ambiguity. Ask questions to make any part of the email clearer if
+ needed.")
+
+(defvar historian-directive
+ "I want you to act as a historian and political scientist. You will research and analyze cultural, economic, political, and social events in the past, collect data from primary sources, and use the information to explain what happened during various periods of history, identify historical patterns, and explain plainly how the events of history inform our times today.")
(defvar chat-directive
"I want you to act as an old friend and highly intelligent person who is good at conversation. You are deeply
@@ -137,7 +141,7 @@ straightforward, and clear language with little ambiguity. Ask questions to make
(:map gptel-mode-map
("C-<return>" . gptel-send))
:custom
- (gptel-default-directive 'code-only)
+ (gptel-default-directive 'default-directive)
(gptel-default-mode 'org-mode)
(gptel-expert-commands t)
(gptel-track-media t)
@@ -150,12 +154,15 @@ straightforward, and clear language with little ambiguity. Ask questions to make
(setq gptel-directives
`((default . ,default-directive)
(coder . ,coder-directive)
- (reviewer . ,reviewer-directive)
- (qa . ,qa-directive)
- (proofreader . ,proofreader-directive)
+ (chat . ,chat-directive)
+ (accountant . ,accountant-directive)
+ (proofreader . ,proofreader-directive)
(email . ,email-directive)
+ (qa . ,qa-directive)
(contractor . ,contractor-directive)
- (chat . ,chat-directive)))
+ (historian . ,historian-directive)
+ (reviewer . ,reviewer-directive)
+ ))
;; Dynamic user prefix for org-mode heading (string, refreshed just before send)
(defun cj/gptel--fresh-org-prefix ()
diff --git a/modules/custom-functions.el b/modules/custom-functions.el
index 710623fe..16b68c51 100644
--- a/modules/custom-functions.el
+++ b/modules/custom-functions.el
@@ -435,16 +435,31 @@ and all articles are considered minor words."
(while (search-forward "" nil t)
(replace-match "" nil t))))
-;; ----------------------------- Clear Blank Lines -----------------------------
-
-(defun cj/clear-blank-lines (beginning end)
- "Remove blank lines in the region or the buffer if no region is selected.
-BEGINNING and END describe the selected region."
- (interactive "r")
+;; -------------------- Remove Blank Lines Region Or Buffer --------------------
+;; removes lines contiaining whitespace from region or buffer.
+
+(defun cj/delete-blank-lines-region-or-buffer (start end)
+ "Delete all blank lines in the region between START and END.
+Blank lines are lines that contain only whitespace (spaces or tabs).
+If called interactively with an active region, operate on that region.
+If no active region, prompt user before operating on the whole buffer.
+Otherwise signal a user-error and do nothing. The point is restored
+to its original position after deletion."
+ (interactive
+ (if (use-region-p)
+ ;; grab its boundaries if there's a region
+ (list (region-beginning) (region-end))
+ ;; or ask if user intended operating on whole buffer
+ (if (yes-or-no-p "Delete blank lines in entire buffer? ")
+ (list (point-min) (point-max))
+ (user-error "Aborted"))))
(save-excursion
- (goto-char beginning)
- (while (re-search-forward "^[ \t]*\n" end t)
- (replace-match ""))))
+ (save-restriction
+ (widen)
+ ;; Regexp "^[[:space:]]*$" matches lines of zero or more spaces/tabs.
+ (flush-lines "^[[:space:]]*$" start end)))
+ ;; Return nil (Emacs conventions). Point is already restored.
+ nil)
;; ---------------------- Fixup Whitespace Line Or Region ----------------------
@@ -635,8 +650,9 @@ Uses `sortable-time-format' for the formatting the date/time."
(define-key map "A" 'cj/unarrayify)
;; de/duplicate lines
(define-key map "d" 'cj/duplicate-line-or-region)
- (define-key map "D" 'cj/remove-duplicate-lines-from-region-or-buffer)
+ (define-key map "D" 'cj/remove-duplicate-lines-from-region-or-buffer)
+ (define-key map "D" 'cj/remove-duplicate-lines-from-region-or-buffer)
(define-key map ")" #'cj/jump-to-matching-paren)
(define-key map "/" #'cj/replace-fraction-glyphs)
(define-key map "L" #'cj/clear-blank-lines)
diff --git a/modules/help-utils.el b/modules/help-utils.el
index 73fc2add..2048e0f6 100644
--- a/modules/help-utils.el
+++ b/modules/help-utils.el
@@ -37,6 +37,11 @@
(defun cj/local-arch-wiki-search ()
+ "Prompt for an ArchWiki topic and open its local HTML copy in EWW.
+Looks for “*.html” files under \"/usr/share/doc/arch-wiki/html/en\",
+lets you complete on their basenames, and displays the chosen file
+with `eww-browse-url'. If no file is found, reminds you to install
+arch-wiki-docs."
(interactive)
(let* ((dir "/usr/share/doc/arch-wiki/html/en")
(full-filenames (directory-files dir t "\\.html\\'"))
diff --git a/modules/mail-config.el b/modules/mail-config.el
index 122b18de..0ac383ca 100644
--- a/modules/mail-config.el
+++ b/modules/mail-config.el
@@ -9,46 +9,7 @@
;;; Code:
-;; ----------------------- Mu4e View Save All Attachments ----------------------
-;; replacement for the extract function which saves all attachments
-
-(defun cj/mu4e-view-save-all-attachments (&optional msg)
- "Save all attachments from the current email.
-Prompt user for directory, creating if necessary, select all attachments in the
-email, and save them in the specified directory. The optional MSG is only
-provided when calling this function from mu4e's action context. This function is
-intended to be used as a `mu4e-view-action' and/or bound to a key in
-mu4e-view-mode-map."
- (interactive)
- (let ((msg (or msg (mu4e-message-at-point))))
- (let* ((parts (mu4e-view-mime-parts))
- ;; build cons list of candidate mime parts
- (candidates (seq-map
- (lambda (attachment-part)
- (cons ;; (filename . annotation)
- (plist-get attachment-part :filename)
- attachment-part))
- ;; scope to parts with a filename
- (seq-filter
- (lambda (part) (plist-get part :attachment-like))
- parts)))
- (candidates (or candidates (mu4e-warn "No attachments for this message")))
- (files (mapcar 'car candidates)) ;; Select all attachments
- (custom-dir (read-directory-name "Save to directory: ")))
- (unless (file-exists-p custom-dir)
- (make-directory custom-dir t)) ;; t creates parent dirs if needed
- ;; iterate over each file
- (seq-do
- (lambda (fname)
- (let* ((part (cdr (assoc fname candidates)))
- ;; build unique full file path
- (path (mu4e--uniqify-file-name
- (mu4e-join-paths
- custom-dir
- (plist-get part :filename)))))
- ;; save the file
- (mm-save-part-to-file (plist-get part :handle) path)))
- files))))
+(require 'user-constants)
;; ------------------------- Mark All Headers ------------------------
;; convenience function to mark all headers for an action
@@ -63,6 +24,7 @@ Prompts user for the action when executing."
;;; ------------------ Smtpmail & Easy PG Assistant -----------------
;; send mail to smtp host from smtpmail temp buffer.
+
(use-package smtpmail
:ensure nil ;; built-in
:defer .5
@@ -88,30 +50,33 @@ Prompts user for the action when executing."
("d" . mu4e-headers-mark-for-delete))
(:map mu4e-view-mode-map
("r" . mu4e-compose-wide-reply)
- ("R" . mu4e-compose-reply)
- ("e" . cj/mu4e-view-save-all-attachments))
+ ("R" . mu4e-compose-reply))
:hook
(mu4e-view-mode . turn-on-visual-line-mode)
:config
- (setq gnus-blocked-images "http") ;; block external images
+ (setq gnus-blocked-images "http") ;; block external images (i.e., 1 px trackers)
(setq mail-user-agent 'mu4e-user-agent) ;; default to mu4e for email
(setq message-citation-line-format "On %a %d %b %Y at %R, %f wrote:\n") ;; helps show up properly in Outlook/Gmail threads
(setq message-citation-line-function 'message-insert-formatted-citation-line)
(setq message-kill-buffer-on-exit t) ;; don't keep message buffers around
- (setq message-signature-file (concat user-emacs-directory "signature")) ;; look for the signature here
(setq mu4e-change-filenames-when-moving t) ;; avoid gmail dup UID issues: https://goo.gl/RTCgVa
(setq mu4e-completing-read-function 'completing-read) ;; use generic completing read, rather than ido
(setq mu4e-compose-context-policy 'ask) ;; ask for context if no context matches
- (setq mu4e-compose-format-flowed t) ;; plain text mails must flow correctly for recipients
+ ;; (setq mu4e-compose-format-flowed t) ;; plain text mails must flow correctly for recipients
(setq mu4e-compose-keep-self-cc t) ;; keep me in the cc list
(setq mu4e-compose-signature-auto-include nil) ;; don't include signature by default
(setq mu4e-confirm-quit nil) ;; don't ask when quitting
(setq mu4e-context-policy 'pick-first) ;; start with the first (default) context
(setq mu4e-headers-auto-update nil) ;; updating headers buffer on email is too jarring
(setq mu4e-root-maildir mail-dir) ;; root directory for all email accounts
+ (setq mu4e-maildir mail-dir) ;; same as above (newer mu4e)
(setq mu4e-sent-messages-behavior 'delete) ;; don't save to "Sent", IMAP does this already
(setq mu4e-show-images t) ;; show embedded images
- (setq mu4e-update-interval nil) ;; don't update automatically
+ (setq mu4e-update-interval nil) ;; disallow automatic checking for new emails
+
+
+ (setq mu4e-compose-format-flowed nil
+ mu4e-html2text-command 'mu4e-shr2text) ;; email conversion to html via shr2text
(setq mu4e-mu-binary (executable-find "mu"))
(setq mu4e-get-mail-command (concat (executable-find "mbsync") " -a")) ;; command to sync mail
@@ -182,19 +147,20 @@ Prompts user for the action when executing."
"My settings for message composition."
(set-fill-column 72)))
- ;; add save-all-attachments to view actions list
- (add-to-list 'mu4e-view-actions
- '("save all attachments" . cj/mu4e-view-save-all-attachments))
+ (defun no-auto-fill ()
+ "Turn off \'auto-fill-mode\'."
+ (auto-fill-mode -1))
+ (add-hook 'mu4e-compose-mode-hook #'no-auto-fill)
;; Always BCC myself
;; http://www.djcbsoftware.nl/code/mu/mu4e/Compose-hooks.html
- (defun cj/add-header ()
- "Add CC: and Bcc: to myself header."
+ (defun cj/add-cc-bcc-header ()
+ "Add CC: and BCC: to myself header."
(save-excursion (message-add-header
(concat "CC: " "\n")
;; pre hook above changes user-mail-address.
(concat "Bcc: " user-mail-address "\n"))))
- (add-hook 'mu4e-compose-mode-hook 'cj/add-header)
+ (add-hook 'mu4e-compose-mode-hook 'cj/add-cc-bcc-header)
;; remap the awkward mml-attach-file to the quicker mail-add-attachment
(define-key mu4e-compose-mode-map [remap mml-attach-file] 'mail-add-attachment)
@@ -206,34 +172,47 @@ Prompts user for the action when executing."
(when (fboundp 'imagemagick-register-types)
(imagemagick-register-types))
- ;; xwidgets not able to be built into emacs on linux
- ;; ;; view in xwidget html rendererer
- ;; (add-to-list 'mu4e-headers-actions
- ;; '("xWidget" . mu4e-action-view-with-xwidget) t)
- ;; (add-to-list 'mu4e-view-actions
- ;; '("xWidget" . mu4e-action-view-with-xwidget) t))
-
) ;; end use-package mu4e
-(defun no-auto-fill ()
- "Turn off \'auto-fill-mode\'."
- (auto-fill-mode -1))
-(add-hook 'mu4e-compose-mode-hook #'no-auto-fill)
-
-;; ;; ----------------------------- Compose Mode Hydra ----------------------------
-;; ;; WIP: menu available in compose mode
-
-;; (defhydra hydra-mu4e-compose (:color blue :timeout 10 :hint nil)
-;; "Compose Mode Menu\n\n"
-;; ("q" quit-window "Quit" :column "")
-;; ("a" mail-add-attachment "Add Attachment" :column "")
-;; ("r" message-new-line-and-reformat "Newline and Reformat" :column "")
-;; ("d" message-delete-not-region "Delete Outside Region" :column ""))
-
-;; (defun mu4e-compose-mode-hook-hydra-setup ()
-;; "Create hydra/menu keybinding when entering compose mode."
-;; (local-set-key (kbd "C-c ?") 'hydra-mu4e-compose/body))
-;; (add-hook 'mu4e-compose-mode-hook 'mu4e-compose-mode-hook-hydra-setup)
+
+;; ---------------------------------- Org-Msg ----------------------------------
+;; user composes org mode; recipient receives html
+
+(use-package org-msg
+ :after (org mu4e)
+ :ensure t
+ :config
+ ;; automatic greetings for html
+ (setq org-msg-greeting-fmt "\nHi%s,\n\n")
+
+ ;; inline CSS, no postamble, no TOC, no stars or footers
+ (setq org-msg-options "html-postamble:nil H:5 num:nil ^:{} toc:nil author:nil email:nil")
+
+ ;; hide org markup, show inline images
+ (setq org-msg-startup "hidestars inlineimages")
+
+ ;; new and html emails get the option for both text and html,
+ ;; text emails get text only replies
+ (setq org-msg-default-alternatives
+ '((new . (text html))
+ (reply-to-html . (text html))
+ (reply-to-text . (text))))
+
+ ;; Convert Org Citations to Blockquote
+ (setq org-msg-convert-citation t)
+
+ ;; Signature (Org Syntax)
+ (setq org-msg-signature "\nCraig\n\n")
+
+ ;; turn on org-msg in all compose buffers
+ (org-msg-mode +1))
+
+
+(advice-add #'mu4e-compose-reply
+ :after (lambda (&rest _) (org-msg-edit-mode)))
+(advice-add #'mu4e-compose-wide-reply
+ :after (lambda (&rest _) (org-msg-edit-mode)))
+
(provide 'mail-config)
;;; mail-config.el ends here
diff --git a/modules/org-config.el b/modules/org-config.el
index 3faea70a..9e55ac6f 100644
--- a/modules/org-config.el
+++ b/modules/org-config.el
@@ -53,6 +53,7 @@ org-archive-subtree-default are placed.")
(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
+ (setq tab-width 8) ;; org-mode complains when tabs aren't @ 8
;; INLINE IMAGES
(setq org-startup-with-inline-images t) ;; preview images by default
diff --git a/modules/org-contacts-config.el b/modules/org-contacts-config.el
deleted file mode 100644
index f6f14c80..00000000
--- a/modules/org-contacts-config.el
+++ /dev/null
@@ -1,27 +0,0 @@
-;;; org-contacts-config.el --- Org Contacts Customizations -*- lexical-binding: t; -*-
-;; author: Craig Jennings <c@cjennings.net>
-;;; Commentary:
-;; Configuration for Org Contacts.
-
-;;; Code:
-
-(use-package org-contacts
- :after (org mu4e)
- :defer .5
- :bind ("C-z C" . org-contacts) ; starts contacts search
- :config
- (setq org-contacts-files (cons contacts-file '()))
-
- (add-to-list 'org-capture-templates
- '("c" "Contact" entry (file+headline contacts-file "Contacts")
- "*%?\n:PROPERTIES:\n:ADDRESS: \n:PHONE: \n:EMAIL: \n:BIRTHDAY: \n:NOTES: \n:END:" :prepend t))
-
- (setq mu4e-contacts-file contacts-file)
-
- (add-to-list 'mu4e-headers-actions
- '("add contact" . mu4e-action-add-org-contact))
- (add-to-list 'mu4e-view-actions
- '("add contact" . mu4e-action-add-org-contact)))
-
-(provide 'org-contacts-config)
-;;; org-contacts-config.el ends here.