dwt1--dotfiles/.doom.d/config.org

37 KiB
Raw Blame History

DT's Doom Emacs Config

ABOUT THIS CONFIG

This is my personal Doom Emacs config. Doom Emacs is a distribution of Emacs that uses the "evil" keybindings (Vim keybindings) and includes a number of nice extensions and a bit of configuration out of the box. I am maintaing this config not just for myself, but also for those that want to explore some of what is possible with Emacs. I will add a lot of examples of plugins and settings, some of them I may not even use personally. I do this because many people following me on YouTube look at my configs as "documentation".

BOOKMARKS AND BUFFERS

Doom Emacs uses 'SPC b' for keybindings related to bookmarks and buffers. Bookmarks are somewhat like registers in that they record positions you can jump to. Unlike registers, they have long names, and they persist automatically from one Emacs session to the next. The prototypical use of bookmarks is to record where you were reading in various files. Regarding buffers, the text you are editing in Emacs resides in an object called a buffer. Each time you visit a file, a buffer is used to hold the files text. Each time you invoke Dired, a buffer is used to hold the directory listing.

(map! :leader
      :desc "List bookmarks"
      "b L" #'list-bookmarks
      :leader
      :desc "Save current bookmarks to bookmark file"
      "b w" #'bookmark-save)

CENTAUR-TABS

To use tabs in Doom Emacs, be sure to uncomment "tabs" in Doom's init.el. Displays tabs at the top of the window similar to tabbed web browsers such as Firefox. I don't actually use tabs in Emacs. I placed this in my config to help others who may want tabs. In the default configuration of Doom Emacs, 'SPC t' is used for "toggle" keybindings, so I choose 'SPC t c' to toggle centaur-tabs. The "g" prefix for keybindings is used for a bunch of evil keybindings in Doom, but "g" plus the arrow keys were not used, so I thought I would bind those for tab navigation. But I did leave the default "g t" and "g T" intact if you prefer to use those for centaur-tabs-forward/backward.

COMMAND DESCRIPTION KEYBINDING
centaur-tabs-local-mode Toggle tabs on/off SPC t c
centaur-tabs-forward Next tab g <right> or g t
centaur-tabs-backward Previous tab g <left> or g T
centaur-tabs-forward-group Next tab group g <down>
centaur-tabs-backward-group Previous tab group g <up>
(setq centaur-tabs-set-bar 'over
      centaur-tabs-set-icons t
      centaur-tabs-gray-out-icons 'buffer
      centaur-tabs-height 24
      centaur-tabs-set-modified-marker t
      centaur-tabs-style "bar"
      centaur-tabs-modified-marker "•")
(map! :leader
      :desc "Toggle tabs on/off"
      "t c" #'centaur-tabs-local-mode)
(evil-define-key 'normal centaur-tabs-mode-map (kbd "g <right>") 'centaur-tabs-forward        ; default Doom binding is 'g t'
                                               (kbd "g <left>")  'centaur-tabs-backward       ; default Doom binding is 'g T'
                                               (kbd "g <down>")  'centaur-tabs-forward-group
                                               (kbd "g <up>")    'centaur-tabs-backward-group)

DIRED

Dired is the file manager within Emacs. Below, I setup keybindings for image previews (peep-dired). Doom Emacs does not use 'SPC d' for any of its keybindings, so I've chosen the format of 'SPC d' plus 'key'.

COMMAND DESCRIPTION KEYBINDING
dired Open dired file manager SPC d d
dired-jump Jump to current directory in dired SPC d j
(in dired) peep-dired Toggle image previews within dired SPC d p
(in dired) dired-view-file View file in dired SPC d v
(in dired) dired-up-directory Go up in the directory tree h
(in dired) dired-find-file Go down in the directory tree (or open if file) l
(in peep-dired-mode) peep-dired-next-file Move to next file in peep-dired-mode j
(in peep-dired-mode) peep-dired-prev-file Move to previous file in peep-dired-mode k
(map! :leader
      :desc "Dired"
      "d d" #'dired
      :leader
      :desc "Dired jump to current"
      "d j" #'dired-jump
      (:after dired
        (:map dired-mode-map
         :leader
         :desc "Peep-dired image previews"
         "d p" #'peep-dired
         :leader
         :desc "Dired view file"
         "d v" #'dired-view-file)))
;; Make 'h' and 'l' go back and forward in dired. Much faster to navigate the directory structure!
(evil-define-key 'normal dired-mode-map
  (kbd "h") 'dired-up-directory
  (kbd "l") 'dired-open-file) ; use dired-find-file instead if not using dired-open package
;; If peep-dired is enabled, you will get image previews as you go up/down with 'j' and 'k'
(evil-define-key 'normal peep-dired-mode-map
  (kbd "j") 'peep-dired-next-file
  (kbd "k") 'peep-dired-prev-file)
(add-hook 'peep-dired-hook 'evil-normalize-keymaps)
;; Get file icons in dired
(add-hook 'dired-mode-hook 'all-the-icons-dired-mode)
;; With dired-open plugin, you can launch external programs for certain extensions
;; For example, I set all .png files to open in 'sxiv' and all .mp4 files to open in 'mpv'
(setq dired-open-extensions '(("gif" . "sxiv")
                              ("jpg" . "sxiv")
                              ("png" . "sxiv")
                              ("mkv" . "mpv")
                              ("mp4" . "mpv")))

DOOM THEME

Setting the theme to doom-one. To try out new themes, I set a keybinding for counsel-load-theme with 'SPC h t'.

(setq doom-theme 'doom-one)
(map! :leader
      :desc "Load new theme"
      "h t" #'counsel-load-theme)

ELFEED

An RSS newsfeed reader for Emacs.

(custom-set-variables
 '(elfeed-feeds
   (quote
    (("https://www.reddit.com/r/linux.rss" reddit linux)
     ("https://www.gamingonlinux.com/article_rss.php" gaming linux)
     ("https://hackaday.com/blog/feed/" hackaday linux)
     ("https://opensource.com/feed" opensource linux)
     ("https://linux.softpedia.com/backend.xml" softpedia linux)
     ("https://itsfoss.com/feed/" itsfoss linux)
     ("https://www.zdnet.com/topic/linux/rss.xml" zdnet linux)
     ("https://www.phoronix.com/rss.php" phoronix linux)
     ("http://feeds.feedburner.com/d0od" omgubuntu linux)
     ("https://www.computerworld.com/index.rss" computerworld linux)
     ("https://www.networkworld.com/category/linux/index.rss" networkworld linux)
     ("https://www.techrepublic.com/rssfeeds/topic/open-source/" techrepublic linux)
     ("https://betanews.com/feed" betanews linux)
     ("http://lxer.com/module/newswire/headlines.rss" lxer linux)
     ("https://distrowatch.com/news/dwd.xml" distrowatch linux)))))

EMMS

One of the media players available for Emacs is emms, which stands for Emacs Multimedia System. By default, Doom Emacs does not use 'SPC a',' so the format I use for these bindings is 'SPC a' plus 'key'.

COMMAND DESCRIPTION KEYBINDING
emms-playlist-mode-go Switch to the playlist buffer SPC a a
emms-pause Pause the track SPC a x
emms-stop Stop the track SPC a s
emms-previous Play previous track in playlist SPC a p
emms-next Play next track in playlist SPC a n
(require 'emms-setup)
(require 'emms-info)
(require 'emms-cue)
(require 'emms-mode-line)
(require 'emms-playing-time)
(emms-all)
(emms-default-players)
(emms-mode-line 1)
(emms-playing-time 1)
(setq emms-source-file-default-directory "~/Music/Non-Classical/70s-80s/"
      emms-playlist-buffer-name "*Music*"
      emms-info-asynchronously t
      emms-source-file-directory-tree-function 'emms-source-file-directory-tree-find)
(map! :leader
      :desc "Go to emms playlist"
      "a a" #'emms-playlist-mode-go
      :leader
      :desc "Emms pause track"
      "a x" #'emms-pause
      :leader
      :desc "Emms stop track"
      "a s" #'emms-stop
      :leader
      :desc "Emms play previous track"
      "a p" #'emms-previous
      :leader
      :desc "Emms play next track"
      "a n" #'emms-next)

EVALUATE ELISP EXPRESSIONS

Changing some keybindings from their defaults to better fit with Doom Emacs, and to avoid conflicts with my window managers which sometimes use the control key in their keybindings. By default, Doom Emacs does not use 'SPC e' for anything, so I choose to use the format 'SPC e' plus 'key' for these (I also use 'SPC e' for 'eww' keybindings).

COMMAND DESCRIPTION KEYBINDING
eval-buffer Evaluate elisp in buffer SPC e b
eval-defun Evaluate the defun containing or after point SPC e d
eval-expression Evaluate an elisp expression SPC e e
eval-last-sexp Evaluate elisp expression before point SPC e l
eval-region Evaluate elisp in region SPC e r
(map! :leader
      :desc "Evaluate elisp in buffer"
      "e b" #'eval-buffer
      :leader
      :desc "Evaluate defun"
      "e d" #'eval-defun
      :leader
      :desc "Evaluate elisp expression"
      "e e" #'eval-expression
      :leader
      :desc "Evaluate last sexpression"
      "e l" #'eval-last-sexp
      :leader
      :desc "Evaluate elisp in region"
      "e r" #'eval-region)

EWW

EWW is the Emacs Web Wowser, the builtin browser in Emacs. Below I set urls to open in a specific browser (eww) with browse-url-browser-function. By default, Doom Emacs does not use 'SPC e' for anything, so I choose to use the format 'SPC e' plus 'key' for these (I also use 'SPC e' for 'eval' keybindings). I chose to use 'SPC s w' for eww-search-words because Doom Emacs uses 'SPC s' for 'search' commands.

(setq browse-url-browser-function 'eww-browse-url)
(map! :leader
      :desc "Eww web browser"
      "e w" #'eww
      :leader
      :desc "Eww reload page"
      "e R" #'eww-reload
      :leader
      :desc "Search web for text between BEG/END"
      "s w" #'eww-search-words)

EXWM

Emacs can be your window manager. You need to install the exwm package (make sure to put 'exwm' in your packages.el in Doom Emacs), and create an exwm.desktop file in /usr/share/xsessions that has 'exec=' set to 'emacs'. Emacs (and exwm) is single threaded so it sometimes does hang. This means that exwm may not be the best window manager if your tasks are resource intensive.

COMMAND DESCRIPTION KEYBINDING
run-shell-command the default run prompt SUPER-&
evil-window-vsplit vertical split SUPER-v
evil-window-split horizontal split SUPER-z
exwm-workspace-switch switch workspace SUPER-w
exwm-workspace-swap swap workspace SUPER-W
exwm-workspace-move move workspace SUPER-CTRL-w
dired dired file manager SUPER-d
eshell the eshell SUPER-RET
dmenu a better run prompt than SUPER-& SUPER-SHIFT-RET
ibuffer ibuffer lets you manage buffers SUPER-b
kill-current-buffer kill current buffer SUPER-B
close-window-or-workspace close window or workspace SUPER-C
evil-window-left change focus to window left SUPER-h
evil-window-down change focus to window down SUPER-j
evil-window-up change focus to window up SUPER-k
evil-window-right change focus to window right SUPER-l
window-move-left move window left SUPER-H
window-move-down move window down SUPER-J
window-move-up move window to up SUPER-K
window-move-right move window right SUPER-L
exwm-workspace-switch-create switch to workspace 0-9 SUPER-(0-9)
exwm-workspace-move-window move window to workspace 0-9 SUPER-SHIFT-(0-9)
(require 'exwm)
(require 'exwm-config)
(exwm-config-default)
(require 'exwm-systemtray)
(exwm-systemtray-enable)
(require 'exwm-randr)
(exwm-randr-enable)
(add-hook 'exwm-randr-screen-change-hook
          (lambda ()
            (start-process-shell-command
              "xrandr" nil "xrandr --output DisplayPort-0 --mode 1920x1080 --pos 0x0 --rotate normal
                                   --output DisplayPort-1 --primary --mode 1920x1080 --pos 1920x0 --rotate normal
                                   --output HDMI-A-0 --mode 1920x1080 --pos 3840x0 --rotate normal")))
(setq exwm-workspace-number 10
      exwm-randr-workspace-output-plist '(0 "DisplayPort-0"
                                          1 "DisplayPort-1"
                                          2 "HDMI-A-0")
      exwm-input-prefix-keys '(?\M-x
                               ?\M-:)
      exwm-input-simulation-keys '(([?\s-F] . [?\C-f])
                                   )
      exwm-input-global-keys '(([?\s-&] . (lambda (command)
                                          (interactive (list (read-shell-command "$ ")))
                                          (start-process-shell-command command nil command)))
                               ;; splits
                               ([?\s-v] . evil-window-vsplit)
                               ([?\s-z] . evil-window-split)
                               ;; managing workspaces
                               ([?\s-w] . exwm-workspace-switch)
                               ([?\s-W] . exwm-workspace-swap)
                               ([?\s-\C-w] . exwm-workspace-move)
                               ;; essential programs
                               ([?\s-d] . dired)
                               ([s-return] . eshell)
                               ([s-S-return] . dmenu)
                               ;; killing buffers and windows
                               ([?\s-b] . ibuffer)
                               ([?\s-B] . kill-current-buffer)
                               ([?\s-C] . +workspace/close-window-or-workspace)
                               ;; change window focus with super+h,j,k,l
                               ([?\s-h] . evil-window-left)
                               ([?\s-j] . evil-window-next)
                               ([?\s-k] . evil-window-prev)
                               ([?\s-l] . evil-window-right)
                               ;; move windows around using SUPER+SHIFT+h,j,k,l
                               ([?\s-H] . +evil/window-move-left)
                               ([?\s-J] . +evil/window-move-down)
                               ([?\s-K] . +evil/window-move-up)
                               ([?\s-L] . +evil/window-move-right)
                               ;; move window to far left or far right with SUPER+CTRL+h,l
                               ([?\s-\C-h] . side-left-window)
                               ([?\s-\C-j] . side-bottom-window)
                               ([?\s-\C-l] . side-right-window)
                               ([?\s-\C-d] . side-window-delete-all)
                               ([?\s-\C-r] . resize-window)
                               ;; switch workspace with SUPER+{0-9}
                               ([?\s-0] . (lambda () (interactive) (exwm-workspace-switch-create 0)))
                               ([?\s-1] . (lambda () (interactive) (exwm-workspace-switch-create 1)))
                               ([?\s-2] . (lambda () (interactive) (exwm-workspace-switch-create 2)))
                               ([?\s-3] . (lambda () (interactive) (exwm-workspace-switch-create 3)))
                               ([?\s-4] . (lambda () (interactive) (exwm-workspace-switch-create 4)))
                               ([?\s-5] . (lambda () (interactive) (exwm-workspace-switch-create 5)))
                               ([?\s-6] . (lambda () (interactive) (exwm-workspace-switch-create 6)))
                               ([?\s-7] . (lambda () (interactive) (exwm-workspace-switch-create 7)))
                               ([?\s-8] . (lambda () (interactive) (exwm-workspace-switch-create 8)))
                               ([?\s-9] . (lambda () (interactive) (exwm-workspace-switch-create 9)))
                               ;; move window workspace with SUPER+SHIFT+{0-9}
                               ([?\s-\)] . (lambda () (interactive) (exwm-workspace-move-window 0)))
                               ([?\s-!] . (lambda () (interactive) (exwm-workspace-move-window 1)))
                               ([?\s-@] . (lambda () (interactive) (exwm-workspace-move-window 2)))
                               ([?\s-#] . (lambda () (interactive) (exwm-workspace-move-window 3)))
                               ([?\s-$] . (lambda () (interactive) (exwm-workspace-move-window 4)))
                               ([?\s-%] . (lambda () (interactive) (exwm-workspace-move-window 5)))
                               ([?\s-^] . (lambda () (interactive) (exwm-workspace-move-window 6)))
                               ([?\s-&] . (lambda () (interactive) (exwm-workspace-move-window 7)))
                               ([?\s-*] . (lambda () (interactive) (exwm-workspace-move-window 8)))
                               ([?\s-\(] . (lambda () (interactive) (exwm-workspace-move-window 9)))
                               ;; setting some toggle commands
                               ([?\s-f] . exwm-floating-toggle-floating)
                               ([?\s-m] . exwm-layout-toggle-mode-line)
                               ([f11] . exwm-layout-toggle-fullscreen)))

Below, I define a few functions that are really just some programs that I want to autostart when logging in to EXWM. Note that I don't execute these until after EXWM has started.

(defun dt/exwm-start-picom ()
  (interactive)
  (start-process-shell-command "picom" nil "picom"))

(defun dt/exwm-start-nm-applet ()
  (interactive)
  (start-process-shell-command "nm-applet" nil "nm-applet"))

(defun dt/exwm-start-volume-icon ()
  (interactive)
  (start-process-shell-command "volume-icon" nil "volume-icon"))

(after! exwm-config
  (dt/exwm-start-picom)
  (dt/exwm-start-nm-applet)
  (dt/exwm-start-volume-icon))

FONTS

Settings related to fonts within Doom Emacs:

  • 'doom-font' standard monospace font that is used for most things in Emacs.
  • 'doom-variable-pitch-font' variable font which is useful in some Emacs plugins.
  • 'doom-big-font' used in doom-big-font-mode; useful for presentations.
  • 'font-lock-comment-face' for comments.
  • 'font-lock-keyword-face' for keywords with special significance, like for and if in C.
(setq doom-font (font-spec :family "SauceCodePro Nerd Font Mono" :size 15)
      doom-variable-pitch-font (font-spec :family "Ubuntu" :size 15)
      doom-big-font (font-spec :family "SauceCodePro Nerd Font Mono" :size 24))
(after! doom-themes
  (setq doom-themes-enable-bold t
        doom-themes-enable-italic t))
(custom-set-faces!
  '(font-lock-comment-face :slant italic)
  '(font-lock-keyword-face :slant italic))

IVY

Ivy is a generic completion mechanism for Emacs.

IVY-POSFRAME

Ivy-posframe is an ivy extension, which lets ivy use posframe to show its candidate menu. Some of the settings below involve:

  • ivy-posframe-display-functions-alist sets the display position for specific programs
  • ivy-posframe-height-alist sets the height of the list displayed for specific programs

Available functions (positions) for 'ivy-posframe-display-functions-alist'

  • ivy-posframe-display-at-frame-center
  • ivy-posframe-display-at-window-center
  • ivy-posframe-display-at-frame-bottom-left
  • ivy-posframe-display-at-window-bottom-left
  • ivy-posframe-display-at-frame-bottom-window-center
  • ivy-posframe-display-at-point
  • ivy-posframe-display-at-frame-top-center

NOTE: If the setting for 'ivy-posframe-display' is set to 'nil' (false), anything that is set to 'ivy-display-function-fallback' will just default to their normal position in Doom Emacs (usually a bottom split). However, if this is set to 't' (true), then the fallback position will be centered in the window.

(require 'ivy-posframe)
(setq ivy-posframe-display-functions-alist
      '((swiper                     . ivy-posframe-display-at-point)
        (complete-symbol            . ivy-posframe-display-at-point)
        (counsel-M-x                . ivy-display-function-fallback)
        (counsel-esh-history        . ivy-posframe-display-at-window-center)
        (counsel-describe-function  . ivy-display-function-fallback)
        (counsel-describe-variable  . ivy-display-function-fallback)
        (counsel-find-file          . ivy-display-function-fallback)
        (counsel-recentf            . ivy-display-function-fallback)
        (counsel-register           . ivy-posframe-display-at-frame-bottom-window-center)
        (dmenu                      . ivy-posframe-display-at-frame-top-center)
        (nil                        . ivy-posframe-display))
      ivy-posframe-height-alist
      '((swiper . 20)
        (dmenu . 20)
        (t . 10)))
(ivy-posframe-mode 1) ; 1 enables posframe-mode, 0 disables it.

IVY KEYBINDINGS

By default, Doom Emacs does not use 'SPC v', so the format I use for these bindings is 'SPC v' plus 'key'.

(map! :leader
      :desc "Ivy push view"
      "v p" #'ivy-push-view
      :leader
      :desc "Ivy switch view"
      "v s" #'ivy-switch-view)

LINE SETTINGS

I have toggled display-line-numbers-type so I have line numbers displayed. Doom Emacs uses 'SPC t' for "toggle" commands, so I choose 'SPC t t' for toggle-truncate-lines.

(setq display-line-numbers-type t)
(map! :leader
      :desc "Toggle truncate lines"
      "t t" #'toggle-truncate-lines)

MANPAGES

(require 'ox-groff)

MASTODON

Mastodon.el is a mastodon client for Emacs. Note that I wrapped my settings with (after! mastodon). Without this, my settings for the mastodon instance that I use would be overwritten by the default settings for this module, which is "mastodon.social".

(after! mastodon
  (setq mastodon-instance-url "https://mastodon.technology/"))

MD4RD

An Emacs reddit client that stands for Mode For Reddit. Below, I'm setting the subreddits that I'm following.

(setq md4rd-subs-active '(archlinux commandline DistroTube DoomEmacs emacs freesoftware lbry linux linux4noobs linuxmasterrace linnuxquestions orgmode qutebrowser suckless Ubuntu unixporn UsabilityPorn vim xmonad))

MU4E

Setting up mu4e which is an email client that works within emacs. You must install mu4e and mbsync through your Linux distribution's package manager. Setting up smtp for sending mail. Make sure the gnutls command line utils are installed. Package 'gnutls-bin' in Debian/Ubuntu, and 'gnutls' in Arch.

(add-to-list 'load-path "/usr/local/share/emacs/site-lisp/mu4e")
(require 'mu4e)
(require 'smtpmail)
(setq mu4e-get-mail-command "mbsync -c ~/.emacs.d/mu4e/.mbsyncrc -a"
      mu4e-update-interval  300
      user-mail-address "derek@distrotube.com"
      user-full-name  "Derek Taylor"
      mu4e-compose-signature
       (concat
         "Derek Taylor\n"
         "http://www.youtube.com/DistroTube\n")
      message-send-mail-function 'smtpmail-send-it
      starttls-use-gnutls t
      smtpmail-starttls-credentials '(("smtp.1and1.com" 587 nil nil))
      smtpmail-auth-credentials '(("smtp.1and1.com" 587 "derek@distrotube.com" nil))
      smtpmail-default-smtp-server "smtp.1and1.com"
      smtpmail-smtp-server "smtp.1and1.com"
      smtpmail-smtp-service 587
      mu4e-sent-folder "/Sent"
      mu4e-drafts-folder "/Drafts"
      mu4e-trash-folder "/Trash"
      mu4e-refile-folder "/All Mail"
      mu4e-maildir-shortcuts
      '(("/derek-distrotube/Inbox"    . ?i)
        ("/derek-distrotube/Sent"     . ?s)
        ("/derek-distrotube/All Mail" . ?a)
        ("/derek-distrotube/Trash"    . ?t)))

NEOTREE

Neotree is a file tree viewer. When you open neotree, it jumps to the current file thanks to neo-smart-open. The neo-window-fixed-size setting makes the neotree width be adjustable. Doom Emacs had no keybindings set for neotree. Since Doom Emacs uses 'SPC t' for 'toggle' keybindings, I used 'SPC t n' for toggle-neotree.

(after! neotree
  (setq neo-smart-open t
        neo-window-fixed-size nil))
(after! doom-themes
  (setq doom-neotree-enable-variable-pitch t))
(map! :leader
      :desc "Toggle neotree file viewer"
      "t n" #'toggle-neotree)

OPEN SPECIFIC FILES

Keybindings to open files that I work with all the time using the find-file command, which is the interactive file search that opens with 'C-x C-f' in GNU Emacs or 'SPC f f' in Doom Emacs. These keybindings use find-file non-interactively since we specify exactly what file to open. The format I use for these bindings is 'SPC -' plus 'key' since Doom Emacs does not use these keybindings.

PATH TO FILE DESCRIPTION KEYBINDING
~/Org/agenda.org Edit agenda file SPC - a
~/.doom.d/config.org" Edit doom config.org SPC - c
~/.doom.d/aliases" Edit eshell aliases SPC - e
~/.doom.d/init.el" Edit doom init.el SPC - i
~/.doom.d/packages.el" Edit doom packages.el SPC - p
(map! :leader
      :desc "Edit agenda file"
      "- a" #'(lambda () (interactive) (find-file "~/Org/agenda.org"))
      :leader
      :desc "Edit doom config.org"
      "- c" #'(lambda () (interactive) (find-file "~/.doom.d/config.org"))
      :leader
      :desc "Edit eshell aliases"
      "- e" #'(lambda () (interactive) (find-file "~/.doom.d/aliases"))
      :leader
      :desc "Edit doom init.el"
      "- i" #'(lambda () (interactive) (find-file "~/.doom.d/init.el"))
      :leader
      :desc "Edit doom packages.el"
      "- p" #'(lambda () (interactive) (find-file "~/.doom.d/packages.el")))

ORG MODE

Note that I wrapped most of this in (after! org). Without this, my settings might be evaluated too early, which will result in my settings being overwritten by Doom's defaults. I have also enabled org-journal by adding (+journal) to the org section of my Doom Emacs init.el.

(after! org
  (require 'org-bullets)  ; Nicer bullets in org-mode
  (add-hook 'org-mode-hook (lambda () (org-bullets-mode 1)))
  (setq org-directory "~/Org/"
        org-agenda-files '("~/Org/agenda.org")
        org-default-notes-file (expand-file-name "notes.org" org-directory)
        org-ellipsis " ▼ "
        org-log-done 'time
        org-journal-dir "~/Org/journal/"
        org-journal-date-format "%B %d, %Y (%A)"
        org-journal-file-format "%Y-%m-%d.org"
        org-hide-emphasis-markers t
        ;; ex. of org-link-abbrev-alist in action
        ;; [[arch-wiki:Name_of_Page][Description]]
        org-link-abbrev-alist    ; This overwrites the default Doom org-link-abbrev-list
          '(("google" . "http://www.google.com/search?q=")
            ("arch-wiki" . "https://wiki.archlinux.org/index.php/")
            ("ddg" . "https://duckduckgo.com/?q=")
            ("wiki" . "https://en.wikipedia.org/wiki/"))
        org-todo-keywords        ; This overwrites the default Doom org-todo-keywords
          '((sequence
             "TODO(t)"           ; A task that is ready to be tackled
             "BLOG(b)"           ; Blog writing assignments
             "GYM(g)"            ; Things to accomplish at the gym
             "PROJ(p)"           ; A project that contains other tasks
             "VIDEO(v)"          ; Video assignments
             "WAIT(w)"           ; Something is holding up this task
             "|"                 ; The pipe necessary to separate "active" states and "inactive" states
             "DONE(d)"           ; Task has been completed
             "CANCELLED(c)" )))) ; Task has been cancelled

I was tired of having to run org-babel-tangle after saving my literate dotfiles. So the following function runs org-babel-tangle upon saving any org-mode buffer. This is asynchronous meaning that it dispatches the tangle function to a subprocess, so that the main Emacs is not blocked while it runs.

(defun dt/org-babel-tangle-async (file)
  "Invoke `org-babel-tangle-file' asynchronously."
  (message "Tangling %s..." (buffer-file-name))
  (async-start
   (let ((args (list file)))
  `(lambda ()
        (require 'org)
        ;;(load "~/.emacs.d/init.el")
        (let ((start-time (current-time)))
          (apply #'org-babel-tangle-file ',args)
          (format "%.2f" (float-time (time-since start-time))))))
   (let ((message-string (format "Tangling %S completed after " file)))
     `(lambda (tangle-time)
        (message (concat ,message-string
                         (format "%s seconds" tangle-time)))))))

(defun dt/org-babel-tangle-current-buffer-async ()
  "Tangle current buffer asynchronously."
  (dt/org-babel-tangle-async (buffer-file-name)))

REGISTERS

Emacs registers are compartments where you can save text, rectangles and positions for later use. Once you save text or a rectangle in a register, you can copy it into the buffer once or many times; once you save a position in a register, you can jump back to that position once or many times. The default GNU Emacs keybindings for these commands (with the exception of counsel-register) involves 'C-x r' followed by one or more other keys. I wanted to make this a little more user friendly, and since I am using Doom Emacs, I choose to replace the 'C-x r' part of the key chords with 'SPC r'.

COMMAND DESCRIPTION KEYBINDING
copy-to-register Copy to register SPC r c
frameset-to-register Frameset to register SPC r f
insert-register Insert contents of register SPC r i
jump-to-register Jump to register SPC r j
list-registers List registers SPC r l
number-to-register Number to register SPC r n
counsel-register Interactively choose a register SPC r r
view-register View a register SPC r v
window-configuration-to-register Window configuration to register SPC r w
increment-register Increment register SPC r +
point-to-register Point to register SPC r SPC
(map! :leader
      :desc "Copy to register"
      "r c" #'copy-to-register
      :leader
      :desc "Frameset to register"
      "r f" #'frameset-to-register
      :leader
      :desc "Insert contents of register"
      "r i" #'insert-register
      :leader
      :desc "Jump to register"
      "r j" #'jump-to-register
      :leader
      :desc "List registers"
      "r l" #'list-registers
      :leader
      :desc "Number to register"
      "r n" #'number-to-register
      :leader
      :desc "Interactively choose a register"
      "r r" #'counsel-register
      :leader
      :desc "View a register"
      "r v" #'view-register
      :leader
      :desc "Window configuration to register"
      "r w" #'window-configuration-to-register
      :leader
      :desc "Increment register"
      "r +" #'increment-register
      :leader
      :desc "Point to register"
      "r SPC" #'point-to-register)

REMOTE CONNECTIONS

Keybindings for ssh'ing into remote machines. By default, Doom Emacs does not use 'SPC \', so the format I use for these bindings is 'SPC \' plus 'key'.

DESCRIPTION KEYBINDING
Ssh into distrotube.com SPC \ d
Ssh into my nextcloud SPC \ n
(map! :leader
      :desc "Ssh into distrotube.com"
      "\\ d" #'(lambda () (interactive) (find-file "/scp:derek@distrotube.com"))
      :leader
      :desc "Ssh into my nextcloud"
      "\\ n" #'(lambda () (interactive) (find-file "/scp:derek@distrotube.net")))

SHELLS

Settings for the various shells and terminal emulators within Emacs.

  • 'shell-file-name' sets the shell to be used in M-x shell, M-x term, M-x ansi-term and M-x vterm.
  • 'eshell-aliases-file' sets an aliases file for the eshell.
(setq shell-file-name "/bin/fish"
      eshell-aliases-file "~/.doom.d/aliases"
      eshell-history-size 5000
      eshell-buffer-maximum-lines 5000
      eshell-hist-ignoredups t
      eshell-scroll-to-bottom-on-input t
      eshell-destroy-buffer-when-process-dies t
      eshell-visual-commands'("bash" "fish" "htop" "ssh" "zsh")
      vterm-max-scrollback 5000)
(map! :leader
      :desc "Counsel eshell history"
      "e h" #'counsel-esh-history)

SPLITS

I set splits to default to opening on the right using 'prefer-horizontal-split'. I set a keybinding for 'clone-indirect-buffer-other-window' for when I want to have the same document in two splits. The text of the indirect buffer is always identical to the text of its base buffer; changes made by editing either one are visible immediately in the other. But in all other respects, the indirect buffer and its base buffer are completely separate. For example, I can fold one split but other will be unfolded.

(defun prefer-horizontal-split ()
  (set-variable 'split-height-threshold nil t)
  (set-variable 'split-width-threshold 40 t)) ; make this as low as needed
(add-hook 'markdown-mode-hook 'prefer-horizontal-split)
(map! :leader
      :desc "Clone indirect buffer other window"
      "b c" #'clone-indirect-buffer-other-window)

SUBLIMITY

The sublimity extension offers Sublime-like smooth scrolling and an experimental minimap. You can also require sublimity-attractive if you want to center everything for a distraction-free mode. I do not use this extension, hence the reason I have sublimity-mode set to 0. Set this to 1 to enable it.

(require 'sublimity-scroll)
(require 'sublimity-map)
(require 'sublimity-attractive)
(sublimity-mode 0)

WINNER MODE

Winner mode has been included with GNU Emacs since version 20. This is a global minor mode and, when activated, it allows you to “undo” (and “redo”) changes in the window configuration with the key commands 'SCP w <left>' and 'SPC w <right>'.

(map! :leader
      :desc "Winner redo"
      "w <right>" #'winner-redo
      :leader
      :desc "Winner undo"
      "w <left>" #'winner-undo)