diff --git a/emacs/.config/doom/+mail.el b/emacs/.config/doom/+mail.el index 5fd03c5..65b576c 100644 --- a/emacs/.config/doom/+mail.el +++ b/emacs/.config/doom/+mail.el @@ -20,6 +20,7 @@ (map! (:leader (:prefix "e" + :desc "Send queued mail" "s" #'smtpmail-send-queued-mail :desc "Open (i)nbox" "i" #'=notmuch :desc "Open (n)otmuch" "n" #'notmuch :desc "(C)ompose mail" "c" #'notmuch-mua-new-mail)))) @@ -450,6 +451,7 @@ matched." ;;; Setup sending email with msmtp (setq send-mail-function 'sendmail-send-it sendmail-program "/usr/local/bin/msmtp" + smtpmail-queue-mail t mail-specify-envelope-from t message-sendmail-f-is-evil t message-sendmail-envelope-from 'header diff --git a/emacs/.config/doom/config.el b/emacs/.config/doom/config.el new file mode 100644 index 0000000..c429179 --- /dev/null +++ b/emacs/.config/doom/config.el @@ -0,0 +1,333 @@ +(add-to-list 'default-frame-alist '(inhibit-double-buffering . t)) + +(setq user-full-name "Colin Powell" + user-mail-address "colin@unbl.ink") + +(setq doom-font (font-spec :family "FuraCode Nerd Font Mono" :size 12)) +(setq doom-big-font (font-spec :family "FuraCode Nerd Font Mono" :size 17)) +(setq doom-theme 'kaolin-aurora) + +;; Applies to current frame +(set-frame-parameter nil 'internal-border-width 20) ; applies to the current frame +;; If we create new frames (via emacsclient) this will do the trick +(add-to-list 'default-frame-alist '(internal-border-width . 20)) +;; Dash highlighting +(after! dash (dash-enable-font-lock)) + +;; Dash highlighting +(after! dash (dash-enable-font-lock)) + +(map! ;; Easier window movement + :n "C-h" 'evil-window-left + :n "C-j" 'evil-window-down + :n "C-k" 'evil-window-up + :n "C-l" 'evil-window-right + + (:map evil-treemacs-state-map + "C-h" 'evil-window-left + "C-l" 'evil-window-right) + + :leader + (:prefix "f" + :desc "Find file in dotfiles" "t" #'+hlissner/find-in-dotfiles + :desc "Browse dotfiles" "T" #'+hlissner/browse-dotfiles) + (:prefix "t" + :desc "Switch themes" "t" #'load-theme) + (:prefix "o" + :desc "Elfeed feed reader" "f" #'elfeed + :desc "Hckrnews" "h" #'hackernews + :desc "Lobste.rs" "l" #'ivy-lobsters) + (:prefix "b" + :desc "Black format buffer" "f" #'blacken-buffer + :desc "isort buffer" "I" #'py-isort-buffer + :desc "Links in buffer" "l" #'ace-link-org) + (:prefix "s" + :desc "Search project TODOs" "t" #'+ivy/tasks + :desc "Search the web" "w" #'web-search + :desc "Goto URL in eww" "u" #'eww-browse-url + :desc "Search in eww" "3" #'eww-search-words + :desc "Search all the things" "g" #'deadgrep)) + +(setq wttrin-default-cities '("Castine, ME" "San Francisco" "Thessaloniki")) +(setq wttrin-default-accept-language '("Accept-Language" . "en-US")) + +(map! + (:leader + (:prefix "o" + :desc "Weather" "w" #'wttrin))) + +;; app/search +(after! web-search + (push '("Searx" "http://search.unbl.ink/?q=%s") + web-search-providers) + (setq web-search-default-provider "Searx")) + +;; app/eglot +;; Back to eglot ... +(add-hook 'foo-mode-hook 'eglot-ensure) + +(setq libmpdel-hostname "mpd.unbl.ink") + +(defun mpdel-playlist-play () + "Start playing the song at point." + (interactive) + (if (derived-mode-p 'mpdel-playlist-current-playlist-mode) + (libmpdel-play-song (navigel-entity-at-point)) + (mpdel-core-insert-current-playlist))) + +(map! :leader + (:prefix "-" + :desc "MPD Open playlist" "-" #'mpdel-playlist-open + :desc "MPD Remove at point" "d" #'mpdel-playlist-delete + :desc "MPD Start at point" "s" #'mpdel-playlist-play + :desc "MPD Next track" "n" #'libmpdel-playback-next + :desc "MPD Previous track" "p" #'libmpdel-playback-previous)) + +;; app/rss +(add-hook! 'elfeed-show-mode-hook (text-scale-set 1.5)) + +(setq rmh-elfeed-org-files (list "~/org/elfeed.org") + elfeed-search-filter "@1-week-ago +unread ") + +(defun elfeed-search-format-date (date) + (format-time-string "%Y-%m-%d %H:%M" (seconds-to-time date))) + +(run-with-timer 0 (* 30 60) 'elfeed-update) + +(setq httpd-host "0.0.0.0") +(setq httpd-port 10000) + +(add-hook 'prog-mode-hook #'goto-address-mode) ;; Linkify links! + +;;; It is the opposite of fill-paragraph +(defun unfill-paragraph () + "Takes a multi-line paragraph and makes it into a single line of text." + (interactive) + (let ((fill-column (point-max))) + (fill-paragraph nil))) + +;; Handy key definition +(define-key global-map "\M-z" 'unfill-paragraph) + +;; A rainbow cat, why not? +(nyan-mode) + +;; Show the cursor when we make jumps, I'm too old for this shit. +(beacon-mode) + +;; Emojis, fuck me. +(add-hook 'after-init-hook #'global-emojify-mode) + +;; PlantUML is awesome for quick diagrams +(add-to-list 'auto-mode-alist '("\\.plantuml\\'" . plantuml-mode)) + +;; Timezone location strings at http://worldtime.io +(setq display-time-world-list '(("America/Los_Angeles" "San Francisco") + ("America/Tegucigalpa" "Tegucigalpa") + ("America/New_York" "New York") + ("Europe/London" "London") + ("Europe/Warsaw" "Warsaw") + ("Europe/Kiev" "Lviv"))) + +(setq +workspaces-switch-project-function #'ignore + +format-on-save-enabled-modes '(python-mode) + +pretty-code-enabled-modes '(emacs-lisp-mode org-mode)) + +;; tools/deft +(setq deft-extensions '("org")) +(setq deft-directory "~/org") + +(after! org + (setq org-directory (expand-file-name "~/org/") + org-agenda-files (list org-directory) + org-agenda-window-setup 'only-window + org-pretty-entities t + org-log-done 'time + org-fontify-whole-heading-line t + org-fontify-done-headline t + org-fontify-quote-and-verse-blocks t + org-ellipsis "…" + org-capture-templates + '(("i" "Send to inbox" entry (file+headline "~/org/inbox.org" "Inbox") + "* TODO %?\n")) + org-todo-keywords + '((sequence "TODO(t)" "NEXT(n)" "MAYBE(m)" "|" "DONE(d)" "WONTDO(w)")) + org-tag-alist '(("@personal" . ?h) + ("@farm" . ?f) + ("@town" . ?s) + ("@errand" . ?e) + ("@15five" . ?w) + ("@family" . ?m)) + org-modules '(ol-eshell + ol-notmuch + ob-eval + ob-exp + ob-http + org-drill + org-id))) + +;; Refiling +(setq org-refile-targets '((nil :maxlevel . 9) + (org-agenda-files :maxlevel . 9))) +(setq org-outline-path-complete-in-steps nil) ; Refile in a single go +(setq org-refile-use-outline-path t) ; Show full paths for refiling + +;; org-set-tags-command +(setq +inbox-file "~/org/inbox.org") +(defun +open-inbox-file () + (interactive) + "Opens the inbox file" + (find-file +inbox-file)) + +(map! + :leader + :desc "Open inbox" "I" #'+open-inbox-file + :desc "Open today" "T" #'org-roam-today + :desc "Open tomorrow" "N" #'org-roam-tomorrow) + +(map! :leader + (:prefix "f" :desc "Save all org buffers" "a" #'org-save-all-org-buffers)) + +(setq org-agenda-span 5 + org-agenda-start-day "1d") +(defun +show-agenda () + (interactive) + (delete-other-windows) + (with-popup-rules! nil + (org-agenda-list) + (calendar)) + (other-window 1) + (split-window-vertically) + (other-window 1) + (find-file +todo-file)) + +(use-package! org-roam + :commands (org-roam-insert org-roam-find-file org-roam) + :init + (setq org-roam-directory "~/org/") + (map! :leader + :prefix "n" + :desc "Org-Roam-Insert" "i" #'org-roam-insert + :desc "Org-Roam-Find" "/" #'org-roam-find-file + :desc "Org-Roam-Buffer" "r" #'org-roam) + :config + (org-roam-mode +1)) + +(with-eval-after-load 'org-roam + (with-eval-after-load 'company + (with-eval-after-load 'org + (require 'company-org-roam) + (company-org-roam-init)))) + +(require 'justify-kp) +;(setq nov-text-width t) +(setq nov-text-width 80) + +(defun my-nov-window-configuration-change-hook () + (my-nov-post-html-render-hook) + (remove-hook 'window-configuration-change-hook + 'my-nov-window-configuration-change-hook + t)) + +(defun my-nov-post-html-render-hook () + (if (get-buffer-window) + (let ((max-width (pj-line-width)) + buffer-read-only) + (save-excursion + (goto-char (point-min)) + (while (not (eobp)) + (when (not (looking-at "^[[:space:]]*$")) + (goto-char (line-end-position)) + (when (> (shr-pixel-column) max-width) + (goto-char (line-beginning-position)) + (pj-justify))) + (forward-line 1)))) + (add-hook 'window-configuration-change-hook + 'my-nov-window-configuration-change-hook + nil t))) + +(add-hook 'nov-post-html-render-hook 'my-nov-post-html-render-hook) +(add-to-list 'auto-mode-alist '("\\.epub\\'" . nov-mode)) + +(defun my-nov-font-setup () + (face-remap-add-relative 'variable-pitch :family "Liberation Serif" + :size 20 + :height 1.0)) +(add-hook 'nov-mode-hook 'my-nov-font-setup) + +(load! "+mail") ;; Mail stuff + +;; Use word wrap in text emails, because most people suck +(remove-hook 'text-mode-hook #'auto-fill-mode) +(add-hook 'message-mode-hook #'word-wrap-mode) + +(after! eshell + (set-eshell-alias! + "f" "(other-window 1) && find-file $1" + "l" "ls -lh" + "d" "dired $1" + "dc" "docker-compose $*" + "fftest" "cd ~/src/ff/fifteen5 && docker-compose exec app django-admin test -k $*" + "ffsh" "cd ~/src/ff/fifteen5/ && docker-compose exec app django-admin shell_plus" + "ffdj" "cd ~/src/ff/fifteen5/ && docker-compose exec app django-admin $*" + "gl" "(call-interactively 'magit-log-current)" + "gs" "magit-status" + "gc" "magit-commit")) + +(def-package! ranger + :commands (ranger deer ranger-override-dired-fn) + :config + (set-popup-rule! "^\\*ranger" :ignore t)) + +(map! + (:leader + (:prefix "a" + :desc "Ranger" "r" #'ranger + :desc "Deer" "d" #'deer))) + +(add-hook! dired-mode #'ranger-override-dired-fn) ;; Override dired-mode so it uses deer + +(setq mastodon-instance-url "https://mastodon.technology") + +(map! :leader + (:prefix "=" + :desc "Open mastodon" "=" #'mastodon + :desc "Update Mastodon timeline" "u" #'mastodon-tl--update + :desc "Toot to Mastodon" "t" #'mastodon-toot)) + +(use-package slack + :commands (slack-start) + :init + (setq slack-buffer-emojify t) ;; if you want to enable emoji, default nil + (setq slack-prefer-current-team t) + :config + (slack-register-team + :name "15five" + :token (auth-source-pick-first-password + :host "15five.slack.com" + :user "colin.powell@15five.com") + :subscribed-channels '((squad-admin water-cooler))) + (slack-register-team + :name "RAB" + :token (auth-source-pick-first-password + :host "randomaccessbrewery.slack.com" + :user "colin@onec.me") + :subscribed-channels '((the_taps random)))) + +(load! "beancount") +(require 'beancount) +(add-to-list 'auto-mode-alist '("\\.beancount\\'" . beancount-mode)) + +(define-derived-mode + pandoc-view-mode + markdown-mode + "pandoc-view-mode" + "View pandoc processing of docx file using markdown mode." + (erase-buffer) + (let* ((pandoc (executable-find "pandoc"))) + (insert (shell-command-to-string + (concat pandoc " --wrap=none " (shell-quote-argument (buffer-file-name)) " -t markdown")))) + (not-modified) + (read-only-mode t)) + +(add-to-list 'auto-mode-alist '("\\.docx\\'" . pandoc-view-mode)) diff --git a/emacs/.config/doom/config.org b/emacs/.config/doom/config.org index 48e46aa..649d808 100644 --- a/emacs/.config/doom/config.org +++ b/emacs/.config/doom/config.org @@ -404,12 +404,24 @@ There's gotta be a way to get the token out of password-store for this. #+END_SRC * Slack #+BEGIN_SRC emacs-lisp -(slack-register-team - :name "15five" - :token (auth-source-pick-first-password - :host "15five.slack.com" - :user "colin.powell@15five.com") - :subscribed-channels '((squad-admin water-cooler))) +(use-package slack + :commands (slack-start) + :init + (setq slack-buffer-emojify t) ;; if you want to enable emoji, default nil + (setq slack-prefer-current-team t) + :config + (slack-register-team + :name "15five" + :token (auth-source-pick-first-password + :host "15five.slack.com" + :user "colin.powell@15five.com") + :subscribed-channels '((squad-admin water-cooler))) + (slack-register-team + :name "RAB" + :token (auth-source-pick-first-password + :host "randomaccessbrewery.slack.com" + :user "colin@onec.me") + :subscribed-channels '((the_taps random)))) #+END_SRC * Beancount Use Emacs and plain text files for your accounting!