2020-03-25 14:43:39 -04:00
#+TITLE : DOOM Emacs Configuration
This configuration of Emacs is highly opinionated.
* Basics
My identity. Used in a handful of places in Emacs to prepopulate authorship and such.
#+BEGIN_SRC emacs-lisp
(setq user-full-name "Colin Powell"
user-mail-address "colin@unbl.ink")
#+END_SRC
* User interface
** Fonts and themes
I change my default theme almost as often as the weather. I tend to revert back
to Doom One most of the time, but I like the Kaolin themes, as well as Nimbus
for it's retro charm. Nimbus just doesn't look great when I'm tired though.
#+BEGIN_SRC emacs-lisp
2020-06-02 17:32:39 -04:00
(setq doom-font (font-spec :family "FuraCode Nerd Font Mono" :size 14 :weight 'semi-light)
doom-variable-pitch-font (font-spec :family "Source Serif Pro" :size 16)
doom-big-font (font-spec :family "FuraCode Nerd Font Mono" :size 20))
(setq doom-theme 'doom-one)
2020-03-25 14:43:39 -04:00
#+END_SRC
** Borders
Barring the unfortunate end of X11 development and my eventual transition to
wayland and sway, you can pry i3wm from my cold, dead hands. One problem,
however is that when you're trying your best to rice up i3, Emacs needs a padded
border.
#+BEGIN_SRC emacs-lisp
;; Applies to current frame
2020-04-08 00:37:40 -04:00
(set-frame-parameter nil 'internal-border-width 30) ; applies to the current frame
2020-03-25 14:43:39 -04:00
;; If we create new frames (via emacsclient) this will do the trick
2020-04-08 00:37:40 -04:00
(add-to-list 'default-frame-alist '(internal-border-width . 30))
2020-03-25 14:43:39 -04:00
#+END_SRC
2020-04-09 10:31:48 -04:00
** Fringe
#+BEGIN_SRC emacs-lisp
(nyan-mode) ;; progress in the form of a rainbow cat.
(add-hook 'after-init-hook #'global-emojify-mode) ;; emojis?!
(add-hook 'prog-mode-hook #'goto-address-mode) ;; linify links!
#+END_SRC
2020-03-25 14:43:39 -04:00
* Keybindings
#+BEGIN_SRC emacs-lisp
(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 "o"
2020-04-20 15:53:40 -04:00
:desc "(H)ckrnews" "H" #'hackernews
:desc "(R)SS" "R" #'=rss
:desc "(M)ail" "M" #'=notmuch
:desc "(L)obste.rs" "L" #'ivy-lobsters)
2020-03-25 14:43:39 -04:00
(: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 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))
#+END_SRC
* Weather
Wttrin is a pretty funny way to check weather. I like that you can copy and
paste fun a ASCII representations of the day's weather. It's not terribly
accurate though.
#+BEGIN_SRC emacs-lisp
(setq wttrin-default-cities '("Castine, ME" "San Francisco" "Thessaloniki"))
(setq wttrin-default-accept-language '("Accept-Language" . "en-US"))
(map!
(:leader
(:prefix "o"
2020-04-20 15:53:40 -04:00
:desc "(W)eather" "W" #'wttrin)))
2020-03-25 14:43:39 -04:00
#+END_SRC
* Music
Right now, just make sure I can connect to my local Mopidy server via MPDel.
#+BEGIN_SRC emacs-lisp
2020-03-25 23:36:50 -04:00
(setq libmpdel-hostname "mpd.unbl.ink")
2020-03-25 14:43:39 -04:00
(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))
#+END_SRC
2020-06-04 14:32:40 -04:00
* RSS
Here we’ re going to use TinyTinyRSS as a backend store for our RSS feeds.
2020-03-25 14:43:39 -04:00
#+BEGIN_SRC emacs-lisp
2020-04-20 12:55:14 -04:00
(setq elfeed-protocol-ttrss-maxsize 200) ;; bigger than 200 is invalid
2020-04-20 15:53:40 -04:00
(setq elfeed-feeds '("ttrss+https://powellc:hT7nPKAHa^fYwXZ*@reader.unbl.ink"))
2020-03-25 14:43:39 -04:00
2020-04-20 15:53:40 -04:00
(setq elfeed-log-level 'debug)
2020-04-20 12:55:14 -04:00
(elfeed-protocol-enable)
2020-04-06 13:51:16 -04:00
2020-04-20 15:53:40 -04:00
;; Schedule feed update for every day at 3PM
2020-06-04 14:32:40 -04:00
(run-at-time "15 min" nil 'elfeed-update)
2020-04-20 15:53:40 -04:00
#+END_SRC
Then wel’ ll setup some nice defaults and font settings for viewing feeds in Elfeed.
#+BEGIN_SRC emacs-lisp
(setq elfeed-search-filter "@2-days-ago +unread")
2020-03-27 09:58:58 -04:00
(defun elfeed-search-format-date (date)
(format-time-string "%Y-%m-%d %H:%M" (seconds-to-time date)))
2020-04-09 08:41:27 -04:00
; Serif font in Elfeed
2020-04-20 12:55:14 -04:00
(add-hook! 'elfeed-mode-hook 'variable-pitch-mode)
(add-hook! 'elfeed-show-mode-hook (text-scale-set 1.2))
2020-03-25 14:43:39 -04:00
#+END_SRC
2020-04-09 10:31:48 -04:00
* Formatting
2020-06-04 14:32:40 -04:00
Here we define the opposite function to fill-paragraph and then map it to Meta-z, which helps when undoing fill paragraph moves.
2020-03-25 14:43:39 -04:00
#+BEGIN_SRC emacs-lisp
(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)))
(define-key global-map "\M-z" 'unfill-paragraph)
#+END_SRC
2020-06-04 14:32:40 -04:00
PlantUML is pretty fantastic. This enables a mode for editing plantuml files in Emacs.
2020-03-25 14:43:39 -04:00
#+BEGIN_SRC emacs-lisp
;; PlantUML is awesome for quick diagrams
(add-to-list 'auto-mode-alist '("\\.plantuml\\'" . plantuml-mode))
2020-04-09 10:31:48 -04:00
#+END_SRC
2020-03-25 14:43:39 -04:00
2020-04-09 10:31:48 -04:00
Handy clock to look up what timezone my co-workers are in!
#+BEGIN_SRC emacs-lisp
2020-03-25 14:43:39 -04:00
;; 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")))
#+END_SRC
* Org-mode
2020-03-25 15:06:16 -04:00
** Basic configuration
2020-06-04 14:32:40 -04:00
A handful of mods here clean up org mode. Line numbers don’ t mean much when you’ re folding and unfolding all the time. I also really enjoy the typography of a serif font when I’ m writing a lot of words.
2020-04-08 00:37:40 -04:00
#+BEGIN_SRC emacs-lisp
(add-hook 'org-mode-hook #'doom-disable-line-numbers-h)
2020-03-25 14:43:39 -04:00
(after! org
(setq org-directory (expand-file-name "~/org/ ")
org-agenda-files (list org-directory)
org-pretty-entities t
2020-04-08 00:37:40 -04:00
org-agenda-dim-blocked-tasks nil
2020-03-25 14:43:39 -04:00
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")
2020-03-25 15:06:16 -04:00
"* TODO %?\n"))
2020-03-25 14:43:39 -04:00
org-todo-keywords
'((sequence "TODO(t)" "NEXT(n)" "MAYBE(m)" "|" "DONE(d)" "WONTDO(w)"))
org-modules '(ol-eshell
ol-notmuch
ob-eval
ob-exp
ob-http
org-drill
org-id)))
2020-04-08 00:37:40 -04:00
;; Don’ t display git gutter in org mode
2020-06-02 17:32:39 -04:00
;; With tree folding, it's pretty much useless
2020-04-08 00:37:40 -04:00
(after! git-gutter
(setq git-gutter:disabled-modes '(org-mode image-mode)))
2020-03-25 14:43:39 -04:00
;; 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
2020-03-25 15:06:16 -04:00
#+END_SRC
** Key bindings
2020-06-04 14:32:40 -04:00
I add only two custom mappings to the default org mode maps, a shortcut to my Inbox file and a quick way to save all open org mode files.
2020-03-25 15:06:16 -04:00
#+BEGIN_SRC emacs-lisp
2020-03-25 14:43:39 -04:00
(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
2020-06-04 14:32:40 -04:00
:desc "Save all org buffers" "A" #'org-save-all-org-buffers)
2020-03-25 15:06:16 -04:00
#+END_SRC
** Agenda configuration
#+BEGIN_SRC emacs-lisp
2020-06-04 14:32:40 -04:00
(setq org-agenda-span 3
2020-03-25 15:06:16 -04:00
org-agenda-start-day "1d")
2020-03-25 14:43:39 -04:00
(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))
2020-03-25 15:06:16 -04:00
#+END_SRC
** Org-roam
2020-06-04 14:32:40 -04:00
I am absolutely in love with [[https://org-roam.readthedocs.io/en/develop/ ][Org-roam ]]. Everything about it makes taking notes easier. I just need to level up with Zettels and web publishing of my notes.
2020-03-25 15:06:16 -04:00
#+BEGIN_SRC emacs-lisp
2020-06-04 14:32:40 -04:00
(setq org-roam-directory "~/org/ ")
2020-03-25 14:43:39 -04:00
#+END_SRC
2020-04-10 15:37:54 -04:00
* Novel
2020-03-25 14:43:39 -04:00
Reading novels in Emacs, how novel!
#+BEGIN_SRC emacs-lisp
(require 'justify-kp)
;(setq nov-text-width t)
2020-06-02 17:32:39 -04:00
(setq nov-text-width 100)
2020-03-25 14:43:39 -04:00
(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)
2020-06-02 17:32:39 -04:00
(defun my-nov-font-setup ()
(face-remap-add-relative 'variable-pitch :family "Noto Serif Regular"
:height 1.0
:size 16))
(add-hook 'nov-mode-hook 'my-nov-font-setup)
2020-03-25 14:43:39 -04:00
(add-to-list 'auto-mode-alist '("\\.epub\\'" . nov-mode))
2020-04-10 15:37:54 -04:00
;(add-hook 'nov-mode-hook 'variable-pitch-mode)
2020-03-25 14:43:39 -04:00
#+END_SRC
* Mail
2020-04-09 10:31:48 -04:00
** Basics
2020-03-25 14:43:39 -04:00
I use notmuch to read and write email from within Emacs.
#+BEGIN_SRC emacs-lisp
2020-04-09 10:31:48 -04:00
;(load! "+mail") ;; Mail stuff
; Use w3m to parse HTML email
(setq mm-text-html-renderer 'w3m)
(setq w3m-fill-column 72)
; Kill email message buffers when you close them
(setq message-kill-buffer-on-exit t)
(setq message-auto-save-directory "~/Mail/colin@unbl.ink/Drafts/ ")
(setq message-directory "~/Mail/colin@unbl.ink/ ")
;;; 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
message-sendmail-extra-arguments '("--read-envelope-from")
mail-envelope-from 'header)
#+END_SRC
** Keybindings
#+BEGIN_SRC emacs-lisp
(map! :leader
(:prefix "e"
:desc "(s)end 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))
2020-03-25 14:43:39 -04:00
#+END_SRC
* Eshell
Handful of fun aliases to make working in Eshell almost like a /real/ shell :smile:
#+BEGIN_SRC emacs-lisp
(after! eshell
(set-eshell-alias!
"f" "(other-window 1) && find-file $1"
"l" "ls -lh"
"d" "dired $1"
"gl" "(call-interactively 'magit-log-current)"
"gs" "magit-status"
"gc" "magit-commit"))
#+END_SRC
* Mastodon
There's gotta be a way to get the token out of password-store for this.
#+BEGIN_SRC emacs-lisp
(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))
#+END_SRC
2020-03-27 09:58:47 -04:00
* Slack
2020-03-30 16:15:49 -04:00
** Configure teams
2020-03-27 09:58:47 -04:00
#+BEGIN_SRC emacs-lisp
2020-03-30 16:53:45 -04:00
(use-package! slack
2020-04-01 14:42:30 -04:00
:commands (slack-start)
:init
(setq slack-buffer-emojify t)
(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")
2020-03-30 16:15:49 -04:00
:subscribed-channels '(the_taps random))
(evil-define-key 'normal slack-info-mode-map
",u" 'slack-room-update-messages)
(evil-define-key 'normal slack-mode-map
",c" 'slack-buffer-kill
",ra" 'slack-message-add-reaction
",rr" 'slack-message-remove-reaction
",rs" 'slack-message-show-reaction-users
",pl" 'slack-room-pins-list
",pa" 'slack-message-pins-add
",pr" 'slack-message-pins-remove
",mm" 'slack-message-write-another-buffer
",me" 'slack-message-edit
",md" 'slack-message-delete
",u" 'slack-room-update-messages
",2" 'slack-message-embed-mention
",3" 'slack-message-embed-channel
"\C-n" 'slack-buffer-goto-next-message
"\C-p" 'slack-buffer-goto-prev-message)
(evil-define-key 'normal slack-edit-message-mode-map
",k" 'slack-message-cancel-edit
",s" 'slack-message-send-from-buffer
",2" 'slack-message-embed-mention
",3" 'slack-message-embed-channel))
2020-03-30 16:53:45 -04:00
(use-package! alert
2020-03-30 16:15:49 -04:00
:commands (alert)
2020-03-30 12:12:55 -04:00
:init
2020-03-31 08:28:46 -04:00
(setq alert-default-style 'libnotify))
2020-03-30 16:15:49 -04:00
#+END_SRC
** Key bindings
#+BEGIN_SRC emacs-lisp
(map! :leader
2020-04-06 13:51:16 -04:00
(:prefix "y" ; For (y)acking
2020-03-31 08:28:46 -04:00
:desc "Slack channels" "s" #'slack-start
2020-03-30 16:53:45 -04:00
:desc "Slack channels" "c" #'slack-channel-select
:desc "Slack IMs" "i" #'slack-im-select
2020-03-31 08:28:46 -04:00
:desc "Slack groups" "g" #'slack-group-select
2020-03-30 16:53:45 -04:00
:desc "Slack threads" "t" #'slack-all-threads))
2020-03-27 09:58:47 -04:00
#+END_SRC
2020-03-26 00:03:07 -04:00
* Beancount
Use Emacs and plain text files for your accounting!
2020-03-25 14:43:39 -04:00
#+BEGIN_SRC emacs-lisp
(load! "beancount")
(require 'beancount)
(add-to-list 'auto-mode-alist '("\\.beancount\\'" . beancount-mode))
#+END_SRC
* Pandoc
Here we are trying to auto-translate Word and PDF files to be viewed in Emacs.
#+BEGIN_SRC emacs-lisp
(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))
#+END_SRC
2020-04-10 15:37:54 -04:00
* Magit
#+BEGIN_SRC emacs-lisp
2020-06-02 17:32:39 -04:00
;;(add-hook 'magit-mode-hook #'doom-disable-line-numbers-h)
2020-04-10 15:37:54 -04:00
(setq +magit-hub-features t ;; I want the PR/issue stuff too!
+magit-hub-enable-by-default t) ;; And I want it on by default!
(after! magit
(magit-wip-after-save-mode t)
(magit-wip-after-apply-mode t)
(setq magit-save-repository-buffers 'dontask
magit-circleci-token "097bf0dd808ad9103d489844e37cecffdf967837"
magit-repository-directories '(("~/src/ " . 3)
("~/dotfiles/ " . 0))
magit-popup-display-buffer-action nil ;; Not sure why this is here, wonder what it does
magit-display-file-buffer-function #'switch-to-buffer-other-window
magithub-clone-default-directory "~/src" ;; I want my stuff to clone to ~ /projects
magithub-preferred-remote-method 'ssh_url)) ;; HTTPS cloning is awful, i authenticate with ssh keys.
#+END_SRC