Browse Source

Replace old dotfiles with immutable nixos dotfiles

main
parent
commit
9cc635d6f8
Signed by: chris GPG Key ID: 3025DCBD46F81C0F
  1. 2122
      README.org
  2. BIN
      config/authinfo.gpg
  3. 5
      config/git
  4. 2
      config/gpg-agent.conf
  5. 26
      config/mbsyncrc
  6. 6
      config/mpd.conf
  7. 22
      config/profile
  8. 11
      config/xinitrc
  9. 7
      config/xmodmap
  10. 31
      hosts/acernitro.org
  11. 38
      modules/agenda.org
  12. 56
      modules/capture.org
  13. 45
      modules/cc.org
  14. 55
      modules/conf.org
  15. 33
      modules/dap.org
  16. 89
      modules/dashboard.org
  17. 52
      modules/dired.org
  18. 44
      modules/docker.org
  19. 58
      modules/elfeed.org
  20. 86
      modules/emms.org
  21. 45
      modules/eshell.org
  22. 100
      modules/evil.org
  23. 72
      modules/exwm.org
  24. 123
      modules/fonts.org
  25. 75
      modules/go.org
  26. 68
      modules/gpg.org
  27. 30
      modules/grammar.org
  28. 100
      modules/hugo.org
  29. 80
      modules/ivy.org
  30. 137
      modules/keys.org
  31. 76
      modules/lsp.org
  32. 62
      modules/magit.org
  33. 19
      modules/modeline.org
  34. 150
      modules/mu4e.org
  35. 27
      modules/nix.org
  36. 160
      modules/org.org
  37. 51
      modules/pass.org
  38. 136
      modules/projects.org
  39. 67
      modules/python.org
  40. 55
      modules/reveal.org
  41. 175
      modules/roam.org
  42. 98
      modules/shell.org
  43. 36
      modules/spelling.org
  44. 48
      modules/themes.org
  45. 38
      modules/trash.org
  46. 55
      modules/uml.org
  47. 43
      modules/vterm.org
  48. 165
      modules/x11.org

2122
README.org
File diff suppressed because it is too large
View File

BIN
config/authinfo.gpg

5
config/git

@ -1,5 +0,0 @@
[user]
email = chris@chrishayward.xyz
name = Christopher James Hayward
[github]
user = chayward1

2
config/gpg-agent.conf

@ -1,2 +0,0 @@
allow-emacs-pinentry
allow-loopback-pinentry

26
config/mbsyncrc

@ -1,26 +0,0 @@
# Sync
# :PROPERTIES:
# :header-args: :tangle ../config/mbsyncrc :comments org
# :END:
# This is the *mbsyncrc*[fn:3] file I use to synchronize my local mail with my server.
IMAPStore xyz-remote
Host mail.chrishayward.xyz
User chris@chrishayward.xyz
PassCmd "pass chrishayward.xyz/chris"
SSLType IMAPS
MaildirStore xyz-local
Path ~/.cache/mail/
Inbox ~/.cache/mail/inbox
SubFolders Verbatim
Channel xyz
Master :xyz-remote:
Slave :xyz-local:
Patterns * !Archives
Create Both
Expunge Both
SyncState *

6
config/mpd.conf

@ -1,6 +0,0 @@
music_directory "~/.local/share/media/music"
playlist_directory "~/.local/share/media/playlists"
bind_to_address "localhost"
port "6600"

22
config/profile

@ -1,22 +0,0 @@
# Force colours
# Manually set the terminal type to ~xterm-256color~ for better colours on TTY Emacs.
export TERM=xterm-256color
# Setting up the $PATH
# Ensure ~~/.local/bin~ added to the =$PATH= environment variable.
export PATH=$PATH:~/.local/bin
# Starting Emacs by default on TTY1
# When launching into a new session on ~TTY1~, if the display server is not running, run *StartX*[fn:3]. This will launch the window manager.
if [ -z "${DISPLAY}" ] && [ "${XDG_VTNR}" -eq 1 ]; then
exec startx
fi

11
config/xinitrc

@ -1,11 +0,0 @@
# Config
# :PROPERTIES:
# :header-args: :tangle ../config/xinitrc :comments org
# :END:
# My workflow includes launching Emacs under X11[fn:1] without the use of a display manager, controlling everything within Emacs, while still providing the functionality of a desktop environment.
compton &
xss-lock -- slock &
exec dbus-launch --exit-with-session emacs -mm --debug-init

7
config/xmodmap

@ -1,7 +0,0 @@
clear lock
clear control
keycode 66 = Control_L
add control = Control_L
add Lock = Control_R

31
hosts/acernitro.org

@ -1,31 +0,0 @@
#+TITLE: Acernitro
#+AUTHOR: Christopher James Hayward
#+EMAIL: chris@chrishayward.xyz
#+PROPERTY: header-args:emacs-lisp :tangle acernitro.el :comments org
#+PROPERTY: header-args :results silent :eval no-export :comments org
#+OPTIONS: num:nil toc:nil todo:nil tasks:nil tags:nil
#+OPTIONS: skip:nil author:nil email:nil creator:nil timestamp:nil
The first real hardware to deploy this configuration on. It's an [[https://www.amazon.com/Acer-Nitro-AN515-Laptop-i5-8300H/dp/B07C715KNT][Acer Nitro AN-515]][fn:1] with the [[https://7thzero.com/blog/switch-hybrid-graphics-mode-nvidia-and-intel][NVIDIA / Intel Hybrid GPU]] [fn:2], which is honestly a pain in the ass to deal with. Due to the issues I encountered with this hardware setup, I opted for *easy mode* and installed [[https://ubuntu.com][Ubuntu]][fn:3], setting up the drivers, and then ripping away everything I didn't need.
* Options
+ Set the browser manually
+ Set the language to Canadian english
+ Increase the font size for the high DPI screen
#+begin_src emacs-lisp
(setq dotfiles/browser "firefox"
dotfiles/language "en_CA"
dotfiles/font-size 112)
#+end_src
* Footnotes
[fn:1] https://www.amazon.com/Acer-Nitro-AN515-Laptop-i5-8300H/dp/B07C715KNT
[fn:2] https://7thzero.com/blog/switch-hybrid-graphics-mode-nvidia-and-intel
[fn:3] https://ubuntu.com

38
modules/agenda.org

@ -1,38 +0,0 @@
#+TITLE: Agenda
#+AUTHOR: Christopher James Hayward
#+EMAIL: chris@chrishayward.xyz
#+PROPERTY: header-args:emacs-lisp :tangle agenda.el :comments org
#+PROPERTY: header-args :results silent :eval no-export :comments org
#+OPTIONS: num:nil toc:nil todo:nil tasks:nil tags:nil
#+OPTIONS: skip:nil author:nil email:nil creator:nil timestamp:nil
Agenda integrations for ~org-mode~.
* Config
Integrate the ~org-agenda~ with the ~org-roam~ database, and the rest of the ~org-mode~ contexts throughout the repository:
#+begin_src emacs-lisp
(setq org-agenda-files '("~/.emacs.d/"
"~/.emacs.d/docs/"
"~/.emacs.d/docs/courses/"
"~/.emacs.d/docs/daily/"
"~/.emacs.d/docs/notes/"
"~/.emacs.d/docs/posts/"
"~/.emacs.d/docs/slides/"
"~/.emacs.d/hosts/"
"~/.emacs.d/modules/"))
#+end_src
* Shortcuts
Open an agenda buffer with =SPC a=:
#+begin_src emacs-lisp
(dotfiles/leader
"a" '(org-agenda :which-key "Agenda"))
#+end_src
* Footnotes

56
modules/capture.org

@ -1,56 +0,0 @@
#+TITLE: Capture
#+AUTHOR: Christopher James Hayward
#+EMAIL: chris@chrishayward.xyz
#+PROPERTY: header-args:emacs-lisp :tangle capture.el :comments org
#+PROPERTY: header-args :results silent :eval no-export
#+OPTIONS: num:nil toc:nil todo:nil tasks:nil tags:nil
#+OPTIONS: skip:nil author:nil email:nil creator:nil timestamp:nil
Capturing images, screencasts, screenshots or live-streaming. It's defined in this file.
* Screenshots
Download *screenshot.el*[fn:1] for taking screenshots of highlighted regions or entire buffers.
#+begin_src emacs-lisp
(straight-use-package
'(screenshot
:type git
:host github
:repo "tecosaur/screenshot"))
#+end_src
* Screencasts
Create screencasts with =one-frame-per-action= GIF recording via *Emacs gif screencast*[fn:2].
+ Pause / Resume
+ High Quality
+ Optimized
#+begin_src emacs-lisp
(use-package gif-screencast
:commands (gif-screencast-start-or-stop gif-screencast-toggle-pause)
:custom (gif-screencast-output-directory (concat dotfiles/home "docs/images/")))
#+end_src
* Keybindings
+ Place keybindings for capturing the screen behind =SPC s=.
* Screenshot with =s=
* Screencast with =c=
#+begin_src emacs-lisp
(dotfiles/leader
"s" '(:ignore t :which-key "Screen")
"ss" '(screenshot :which-key "Screenshot")
"sc" '(gif-screencast-start-or-stop :which-key "Screencast"))
#+end_src
* Footnotes
[fn:1] https://github.com/tecosaur/screenshot
[fn:2] https://github.com/takaxp/emacs-gif-screencast

45
modules/cc.org

@ -1,45 +0,0 @@
#+TITLE: C/C++
#+AUTHOR: Christopher James Hayward
#+EMAIL: chris@chrishayward.xyz
#+PROPERTY: header-args:emacs-lisp :tangle cc.el :comments org
#+PROPERTY: header-args:shell :tangle no
#+PROPERTY: header-args :results silent :eval no-export :comments org
#+OPTIONS: num:nil toc:nil todo:nil tasks:nil tags:nil
#+OPTIONS: skip:nil author:nil email:nil creator:nil timestamp:nil
#+begin_quote
The goal of C++ is productivity, this comes in many ways, but the language is designed to aid you as much as possible whiole hindering you as little as possible with arbitrary rules or requirements.
-- Bruce Eckel, Thinking in C++[fn:1]
#+end_quote
* Setup
Make sure all of the required components are installed, and the ~lsp~ and ~dap~ modules have loaded before loading this module.
#+begin_src shell
RUN apt install -y gcc gdb ccls libstdc++
#+end_src
* Config
Use the ~ccls~[fn:2] language server, and the respective Emacs package to interact with the server inside of Emacs. Load the ~babel~ language module and add structure templates for creating C/C++ code blocks inside ~org-mode~.
#+begin_src emacs-lisp
(use-package ccls
:hook ((c-mode c++-mode objc-mode cuda-mode) .
(lambda ()
(require 'ccls)
(lsp-deferred)))
:config (add-to-list 'org-structure-template-alist '("cc" . "src C"))
(add-to-list 'org-structure-template-alist '("cpp" . "src C++"))
(org-babel-do-load-languages 'org-babel-load-languages '((C . t))))
#+end_src
* Footnotes
[fn:1] https://chrishayward.xyz/notes/thinking-in-cpp/
[fn:2] https://github.com/MaskRay/ccls

55
modules/conf.org

@ -1,55 +0,0 @@
#+TITLE: Conf
#+AUTHOR: Christopher James Hayward
#+EMAIL: chris@chrishayward.xyz
#+PROPERTY: header-args:emacs-lisp :tangle conf.el :comments org
#+PROPERTY: header-args:shell :tangle no
#+PROPERTY: header-args :results silent :eval no-export :comments org
#+OPTIONS: num:nil toc:nil todo:nil tasks:nil tags:nil
#+OPTIONS: skip:nil author:nil email:nil creator:nil timestamp:nil
Support for different configuration languages.
* Config
Add support for different configuration languages, or other modules that don't fit in their own module (yet).
** HTTP
Interact with ~HTTP~ endpoints using the ~ob-http~[fn:1] package. You can see how it works in my post here[fn:2]. It adds interactive ~HTTP~ blocks that can output their results in place, within an ~org-mode~ buffer.
#+begin_src emacs-lisp
(use-package ob-http
:after org
:config (org-babel-do-load-languages
'org-babel-load-languages '((http . t))))
#+end_src
** YAML
Support for YAML[fn:3] files.
#+begin_src emacs-lisp
(use-package yaml-mode)
#+end_src
** gRPC
Support for gRPC[fn:4] protocol buffer definition files.
#+begin_src emacs-lisp
(use-package protobuf-mode
:after org
:config (add-to-list 'org-structure-template-alist '("pb" . "src protobuf")))
#+end_src
* Footnotes
[fn:1] https://github.com/zweifisch/ob-http
[fn:2] https://chrishayward.xyz/posts/kanye-as-a-service/
[fn:3] https://emacswiki.org/emacs/YamlMode
[fn:4] https://github.com/protocolbuffers/protobuf/blob/master/editors/protobuf-mode.el

33
modules/dap.org

@ -1,33 +0,0 @@
#+TITLE: Debug Adapter Protocol
#+AUTHOR: Christopher James Hayward
#+EMAIL: chris@chrishayward.xyz
#+PROPERTY: header-args:emacs-lisp :tangle dap.el :comments org
#+PROPERTY: header-args:shell :tangle no
#+PROPERTY: header-args :results silent :eval no-export :comments org
#+OPTIONS: num:nil toc:nil todo:nil tasks:nil tags:nil
#+OPTIONS: skip:nil author:nil email:nil creator:nil timestamp:nil
The Debug Adapter Protocol (DAP) defines the abstract protocol used between a development tool (Emacs) and a debugger[fn:1].
* Config
Use the package ~dap-mode~[fn:2] to add support for the Debug Adapter Protocol[fn:1] inside of Emacs. It has been tested against the following language servers:
+ Java
+ Ruby
+ Python
+ Elixir
+ LLDB (C/C++/Obj-C/Swift)
#+begin_src emacs-lisp
(use-package dap-mode
:commands (dap-debug))
#+end_src
* Footnotes
[fn:1] https://microsoft.github.io/debug-adapter-protocol/
[fn:2] https://github.com/emacs-lsp/dap-mode

89
modules/dashboard.org

@ -1,89 +0,0 @@
#+TITLE: Dashboard
#+AUTHOR: Christopher James Hayward
#+EMAIL: chris@chrishayward.xyz
#+PROPERTY: header-args:emacs-lisp :tangle dashboard.el :comments org
#+PROPERTY: header-args:shell :tangle no
#+PROPERTY: header-args :results silent :eval no-export :comments org
#+OPTIONS: num:nil toc:nil todo:nil tasks:nil tags:nil
#+OPTIONS: skip:nil author:nil email:nil creator:nil timestamp:nil
#+ATTR_ORG: :width 420px
#+ATTR_HTML: :width 420px
#+ATTR_LATEX: :width 420px
[[../docs/images/desktop-example.png]]
Present a *Dashboard*[fn:1] when first launching Emacs. Customize the buttons of the navigator.
* Configuration
Goal of this module is to provide an easily customizable dashboard buffer to display when launching Emacs. I also want it to include some custom links. These are hard coded right now but I want to move them to [[file:../README.org][Options]].
+ Brain @ http://localhost:8080
+ Homepage @ https://chrishayward.xyz
+ Athabasca @ https://login.athabascau.ca/cas/login
+ Bookshelf @ https://online.vitalsource.com
#+begin_src emacs-lisp
(use-package dashboard
:custom (dashboard-center-content t)
(dashboard-set-init-info t)
(dashboard-set-file-icons t)
(dashboard-set-heading-icons t)
(dashboard-set-navigator t)
(dashboard-startup-banner (expand-file-name "~/.emacs.d/docs/images/emacs.png"))
(dashboard-projects-backend 'projectile)
(dashboard-items '((projects . 10) (recents . 10) (agenda . 10)))
(dashboard-navigator-buttons
`(((,(all-the-icons-fileicon "brain" :height 1.1 :v-adjust 0.0)
"Brain" "Knowledge base"
(lambda (&rest _) (browse-url "http://localhost:8080"))))
((,(all-the-icons-material "public" :height 1.1 :v-adjust 0.0)
"Homepage" "Personal website"
(lambda (&rest _) (browse-url "https://chrishayward.xyz"))))
((,(all-the-icons-faicon "university" :height 1.1 :v-adjust 0.0)
"Athabasca" "Univeristy login"
(lambda (&rest _) (browse-url "https://login.athabascau.ca/cas/login"))))
((,(all-the-icons-faicon "book" :height 1.1 :v-adjust 0.0)
"Bookshelf" "Vitalsource bookshelf"
(lambda (&rest _) (browse-url "https://online.vitalsource.com"))))))
:config (dashboard-setup-startup-hook))
#+end_src
** Default buffer
Ensure that the dashboard is the initial buffer.
#+begin_src emacs-lisp
(with-eval-after-load 'dashboard
(setq initial-buffer-choice
(lambda ()
(get-buffer "*dashboard*"))))
#+end_src
** Keybinding
Quickly navigate to the dashboard with =SPC SPC=.
#+begin_src emacs-lisp
(dotfiles/leader
"SPC" '((lambda ()
(interactive)
(switch-to-buffer "*dashboard*"))
:which-key "Dashboard"))
#+end_src
Navigate to the scratch buffer with =SPC C-SPC=.
#+begin_src emacs-lisp
(dotfiles/leader
"C-SPC" '((lambda ()
(interactive)
(switch-to-buffer "*scratch*"))
:which-key "Scratch"))
#+end_src
* Footnotes
[fn:1] https://github.com/emacs-dashboard/emacs-dashboard

52
modules/dired.org

@ -1,52 +0,0 @@
#+TITLE: Dired
#+AUTHOR: Christopher James Hayward
#+EMAIL: chris@chrishayward.xyz
#+PROPERTY: header-args:emacs-lisp :tangle dired.el :comments org
#+PROPERTY: header-args :results silent :eval no-export :comments org
#+OPTIONS: num:nil toc:nil todo:nil tasks:nil tags:nil
#+OPTIONS: skip:nil author:nil email:nil creator:nil timestamp:nil
Emacs has a built-in directory editor.
* Config
Emacs has some really amazing built-in packages, and ~dired~[fn:1] is one of them. It completly coveres everything you would expect from a file manager, but it's not perfect out of the box.
** Current directory
I don't want to press =RET= twice to navigate to the current directory. There's a way to get around this problem with ~jump~, included in the ~dired-x~ package, included with Emacs.
#+begin_src emacs-lisp
(require 'dired-x)
#+end_src
** Reusing the same buffer
By default, ~dired~[fn:1] will create a new buffer each time you press =RET= over a directory. This leads to unwanted buffers all over the place. Avoid this behaviour with ~dired-single~[fn:2], reusing the same ~dired~ buffer.
+ Move up a directory with =h=
+ Open a single buffer with =l=
#+begin_src emacs-lisp
(use-package dired-single
:config (evil-collection-define-key 'normal 'dired-mode-map
"h" 'dired-single-up-directory
"l" 'dired-single-buffer))
#+end_src
* Shortcuts
Open a new dired buffer using the ~jump~ command with =SPC d=.
#+begin_src emacs-lisp
(dotfiles/leader
"d" '(dired-jump :which-key "Dired"))
#+end_src
* Footnotes
[fn:1] https://en.wikipedia.org/wiki/Dired
[fn:2] https://github.com/crocket/dired-single

44
modules/docker.org

@ -1,44 +0,0 @@
#+TITLE: Docker
#+AUTHOR: Christopher James Hayward
#+EMAIL: chris@chrishayward.xyz
#+PROPERTY: header-args:emacs-lisp :tangle docker.el :comments org
#+PROPERTY: header-args:shell :tangle no
#+PROPERTY: header-args :results silent :eval no-export :comments org
#+OPTIONS: num:nil toc:nil todo:nil tasks:nil tags:nil
#+OPTIONS: skip:nil author:nil email:nil creator:nil timestamp:nil
Interact with Docker[fn:1] inside of Emacs.
* Setup
Make sure you have the required components installed on your system before loading the module.
#+begin_src shell
RUN apt install -y docker docker-compose
#+end_src
* Config
It's possible to interact with Docker[fn:1] inside of Emacs through the ~docker.el~[fn:2] plugin. It provides rich support for working with containers, images, compose networks, and has bindings for using machine.
#+begin_src emacs-lisp
(use-package docker
:commands (docker))
#+end_src
* Shortcuts
Open the container management screen with =SPC k=.
#+begin_src emacs-lisp
(dotfiles/leader
"k" '(docker :which-key "Docker"))
#+end_src
* Footnotes
[fn:1] https://docker.com
[fn:2] https://github.com/Silex/docker.el

58
modules/elfeed.org

@ -1,58 +0,0 @@
#+TITLE: Elfeed
#+AUTHOR: Christopher James Hayward
#+EMAIL: chris@chrishayward.xyz
#+PROPERTY: header-args:emacs-lisp :tangle elfeed.el :comments org
#+PROPERTY: header-args:shell :tangle no
#+PROPERTY: header-args :results silent :eval no-export :comments org
Setup a news feed inside of Emacs using ~elfeed~[fn:1], an Emacs web feeds client.
* Setup
+ Add the feed for my website[fn:2] to make sure the RSS feeds are updating correctly
+ Add some subreddits, mostly about ~linux~, ~emacs~ and ~org-mode~
#+begin_src emacs-lisp
(use-package elfeed
:commands (elfeed elfeed-update)
:custom (elfeed-feeds (quote
(("https://hexdsl.co.uk/rss.xml")
("https://lukesmith.xyz/rss.xml")
("https://friendo.monster/rss.xml")
("https://chrishayward.xyz/index.xml")
("https://protesilaos.com/codelog.xml")))))
#+end_src
** Goodies
Extend ~elfeed~[fn:1] with the ~elfeed-goodies~[fn:3] package.
#+begin_src emacs-lisp
(use-package elfeed-goodies
:after elfeed
:custom (elfeed-goodies/entry-pane-size 0.5)
:config (elfeed-goodies/setup))
#+end_src
* Shortcuts
Configure ~elfeed~[fn:1] keybindings behind =SPC l=:
+ Open with =l=
+ Update with =u=
#+begin_src emacs-lisp
(dotfiles/leader
"l" '(:ignore t :which-key "Elfeed")
"ll" '(elfeed :which-key "Open")
"lu" '(elfeed-update :which-key "Update"))
#+end_src
* Footnotes
[fn:1] https://github.com/skeeto/elfeed
[fn:2] https://chrishayward.xyz/index.xml
[fn:3] https://github.com/algernon/elfeed-goodies

86
modules/emms.org

@ -1,86 +0,0 @@
#+TITLE: EMMS
#+AUTHOR: Christopher James Hayward
#+EMAIL: chris@chrishayward.xyz
#+PROPERTY: header-args:emacs-lisp :tangle emms.el :comments org
#+PROPERTY: header-args :results silent :eval no-export :comments org
#+OPTIONS: num:nil toc:nil todo:nil tasks:nil tags:nil
#+OPTIONS: skip:nil author:nil email:nil creator:nil timestamp: nil
EMMS[fn:1] is Emacs as a multimedia player.
* Setup
Make sure you install the required packages on your system before loading the module.
#+begin_src shell
RUN apt install -y mpc mpd mpv
#+end_src
** Music player daemon
:PROPERTIES:
:header-args: :tangle ../config/mpd.conf
:END:
MPD[fn:2] uses a simple text configuration file. Most options only accept a string in " quotes ". The most important option to configure is the ~music_directory~. This is where all of the music ~mpd~[fn:2] will serve exists. It will read the directory recursively.
#+begin_src conf
music_directory "~/.local/share/media/music"
#+end_src
You can configure where ~mpd~[fn:2] will look for playlists. You may want to configure this option if you share your playlists between devices.
#+begin_src conf
playlist_directory "~/.local/share/media/playlists"
#+end_src
It's possible to serve ~mpd~[fn:2] over the network by configuring it to listen on =0.0.0.0=, or by the systems host name. For a local setup, leave it as =localhost=.
#+begin_src conf
bind_to_address "localhost"
port "6600"
#+end_src
*** Deploy the configuration
MPD[fn:2] will look for its configuration in =~/.config/mpd/mpd.conf=, and =/etc/mpd.conf= respectively.
#+begin_src emacs-lisp
(let ((mpd-dir "~/.config/mpd"))
(unless (file-exists-p mpd-dir)
(make-directory mpd-dir t))
(dotfiles/symlink "~/.emacs.d/config/mpd.conf"
(concat mpd-dir "/mpd.conf")))
#+end_src
* Config
Displays and play multimedia from within Emacs with ~emms~[fn:1], using a variety of external players from different sources. It can run as a minimalist player and controlled with commands, or a fully fledged interactive media browser. It can display album art, play streaming media, tag files, search lyrics, and provide ~mpd~[fn:2] connectivity.
#+begin_src emacs-lisp
(use-package emms
:custom (emms-player-mpd-server-name "localhost")
(emms-player-mpd-server-port "6600")
:config (require 'emms-setup)
(require 'emms-player-mpd)
(emms-all)
(emms-default-players)
(add-to-list 'emms-info-functions 'emms-info-mpd)
(add-to-list 'emms-player-list 'emms-player-mpd))
#+end_src
* Shortcuts
Place bindings for ~emms~[fn:1] behind =SPC u=:
#+begin_src emacs-lisp
(dotfiles/leader
"u" '(:ignore t :which-key "EMMS"))
#+end_src
* Footnotes
[fn:1] https://gnu.org/software/emms/
[fn:2] https://musicpd.org

45
modules/eshell.org

@ -1,45 +0,0 @@
#+TITLE: EShell
#+AUTHOR: Christopher James Hayward
#+EMAIL: chris@chrishayward.xyz
#+PROPERTY: header-args:emacs-lisp :tangle eshell.el :comments org
#+PROPERTY: header-args :results silent :eval no-export :comments org
#+OPTIONS: num:nil toc:nil todo:nil tasks:nil tags:nil
#+OPTIONS: skip:nil author:nil email:nil creator:nil timestamp:nil
EShell is a fully POSIX compliant shell written entirely in Emacs Lisp, included with Emacs.
* Config
While not a traditional terminal emulator, it provides a native REPL for Emacs Lisp code, with everything in your configuration available in the environment. Make some slight configurations:
+ Don't highlight the prompt
+ Favour use of system utilities
#+begin_src emacs-lisp
(setq eshell-highlight-prompt nil
eshell-prefer-lisp-functions nil)
#+end_src
* Extras
Implement the lambda prompt for aesthetic purposes with the ~eshell-prompt-extras~ package. Here's an example of what that looks like:
#+begin_example
~/.emacs.d/modules:main*? λ
#+end_example
#+begin_src emacs-lisp
(use-package eshell-prompt-extras
:custom (eshell-prompt-function 'epe-theme-lambda))
#+end_src
* Shortcuts
Open ~eshell~ in the current buffer with =SPC e=:
#+begin_src emacs-lisp
(dotfiles/leader
"e" '(eshell :which-key "EShell"))
#+end_src

100
modules/evil.org

@ -1,100 +0,0 @@
#+TITLE: Evil
#+AUTHOR: Christopher James Hayward
#+EMAIL: chris@chrishayward.xyz
#+PROPERTY: header-args:emacs-lisp :tangle evil.el :comments org
#+PROPERTY: header-args :results silent :eval no-export :comments org
#+OPTIONS: num:nil toc:nil todo:nil tasks:nil tags:nil
#+OPTIONS: skip:nil author:nil email:nil creator:nil timestamp:nil
Transform Emacs into Vim.
* Config
Emacs has some strange default keybindings, which given the age of the project, is not surprising. To overcome this nearly show-stopping hurdle, we transform Emacs into Vim with ~evil~[fn:1], the Extensible VI Layer for Emacs.
#+begin_src emacs-lisp
(use-package evil
:custom (evil-want-integration t) ;; Required for `evil-collection'.
(evil-want-keybinding nil) ;; Same as above
:config (evil-mode +1))
#+end_src
** Improvements
While covering substantial ground towards the goal, the default keybindings implemented in ~evil~[fn:1] alone are lacking compared to what you would expect from Vim. There's a community curated package ~evil-collection~[fn:2] that does a much better job implementing the proper keybindings.
#+begin_src emacs-lisp
(use-package evil-collection
:after evil
:config (evil-collection-init))
#+end_src
** Surround text
Quickly and efficiently surround text with ~evil-surround~[fn:3]. Highlight blocks of text with function definitions, quotations, or any symbol you can input from your keyboard.
#+begin_src emacs-lisp
(use-package evil-surround
:after evil
:config (global-evil-surround-mode 1))
#+end_src
** Line numbering
Relative line numbers are important when using VI emulation keys. You can prefix commands with a number, allowing you to perform that action that number of times. Useful when navigating around pages that are hundreds, or even thousands of lines long.
#+begin_example
5:
4:
3:
2:
1:
156: << CURRENT LINE >>
1:
2:
3:
4:
5:
#+end_example
This behaviour is implemented with ~linum-relative~[fn:4], hooking into the ~display-line-number-mode~ as the backend for good performance in the GUI or TTY.
#+begin_src emacs-lisp
(use-package linum-relative
:commands (linum-relative-global-mode)
:custom (linum-delay t)
(linum-relative-backend 'display-line-numbers-mode))
#+end_src
** Toggle comments
Toggle comments in a language agnostic manner with ~evil-nerd-commenter~[fn:5]. Add a custom binding to =M-;= to mimmic the behaviour in other popular Emacs configuration frameworks. What is =M-?= Called the *Meta* key in Emacs, it typically refers to =Alt=.
#+begin_src emacs-lisp
(use-package evil-nerd-commenter
:after evil
:bind ("M-;" . evilnc-comment-or-uncomment-lines))
#+end_src
* Shortcuts
Toggle relative line numbers with =SPC t l=.
#+begin_src emacs-lisp
(dotfiles/leader
"tl" '(linum-relative-global-mode :which-key "Lines"))
#+end_src
* Footnotes
[fn:1] https://github.com/emacs-evil/evil-mode
[fn:2] https://github.com/emacs-evil/evil-collection
[fn:3] https://github.com/emacs-evil/evil-surround
[fn:4] https://github.com/emacsmirror/linum-relative
[fn:5] https://github.com/redguardtoo/evil-nerd-commenter

72
modules/exwm.org

@ -1,72 +0,0 @@
#+TITLE: EXWM
#+AUTHOR: Christopher James Hayward
#+EMAIL: chris@chrishayward.xyz
#+PROPERTY: header-args:emacs-lisp :tangle exwm.el :comments org
#+PROPERTY: header-args :results silent :eval no-export :comments org
#+OPTIONS: num:nil toc:nil todo:nil tasks:nil tags:nil
#+OPTIONS: skip:nil author:nil email:nil creator:nil timestamp:nil
Emacs can run as a complete tiling window manager for X11.
* Setup
Load the ~x11~ module before loading this module.
* Config
When ~exwm~[fn:1] first launches the ~init-hook~ is executed, allowing us to define some custom logic inside of a hook. Display the time and date, and the battery information, if any is available. I add this here because when I'm running Emacs without ~exwm~[fn:1], information such as the batter and time is typically already available.
#+begin_src emacs-lisp
(defun dotfiles/init-hook ()
(exwm-workspace-switch-create 1)
(setq display-time-and-date t)
(display-battery-mode 1)
(display-time-mode 1))
#+end_src
** Display detection
Enable hot plugging by forcing a profile change with ~autorandr~.
#+begin_src emacs-lisp
(defun dotfiles/update-display ()
"Update the displays by forcing a change through autorandr."
(dotfiles/run-in-background "autorandr --change --force"))
#+end_src
** Window manager
Connect all of the custom hooks and configure the input keys, a custom layer for key captures when Emacs us running as a window manager. Enable ~randr~ support, to function with ~autorandr~, and apply some default bindings.
#+begin_src emacs-lisp
(use-package exwm
:when (window-system)
:custom (exwm-workspace-show-all-buffers t)
(exwm-input-prefix-keys
'(?\M-x
?\C-g
?\C-\ ))
(exwm-input-global-keys
`(([?\s-r] . exwm-reset)
,@(mapcar (lambda (i)
`(,(kbd (format "s-%d" i)) .
(lambda ()
(interactive)
(exwm-workspace-switch-create ,i))))
(number-sequence 1 9))))
:config (require 'exwm-randr)
(exwm-randr-enable)
(add-hook 'exwm-init-hook #'dotfiles/init-hook)
(add-hook 'exwm-randr-screen-change-hook #'dotfiles/update-display)
(add-hook 'exwm-update-class-hook (lambda () (exwm-workspace-rename-buffer exwm-class-name)))
(dotfiles/update-display)
(dotfiles/run-in-background "nitrogen --restore") ;; Update the wallpaper.
(dotfiles/run-in-background "xmodmap") ;; Rebind CTRL and CAPS.
(exwm-enable))
#+end_src
* Footnotes
[fn:1] https://github.com/ch11ng/exwm

123
modules/fonts.org

@ -1,123 +0,0 @@
#+TITLE: Fonts
#+AUTHOR: Christopher James Hayward
#+EMAIL: chris@chrishayward.xyz
#+PROPERTY: header-args:emacs-lisp :tangle fonts.el :comments org
#+PROPERTY: header-args:shell :tangle no
#+PROPERTY: header-args :results silent :eval no-export :comments org
#+OPTIONS: num:nil toc:nil todo:nil tasks:nil tags:nil
#+OPTIONS: skip:nil author:nil email:nil creator:nil timestamp:nil
Unified system font across Emacs.
* Setup
Install the required ~firacode~[fn:1] font before loading the module:
#+begin_src shell
RUN apt install -y fonts-firacode
#+end_src
* Config
Write out the value of ~dotfiles/font~ to all of the available font faces supported by Emacs. By default, this uses ~firacode~[fn:1] for its readability and ligature support. All of the heights are configured to ~dotfiles/font-size~ by default, with further configuration based on the given size possible.
#+begin_src emacs-lisp
(set-face-attribute 'default nil :font dotfiles/font :height dotfiles/font-size)
(set-face-attribute 'fixed-pitch nil :font dotfiles/font :height dotfiles/font-size)
(set-face-attribute 'variable-pitch nil :font dotfiles/font :height dotfiles/font-size)
#+end_src
** Icons
Emacs feels more modern with prioritized icon fonts, available in the ~all-the-icons~[fn:2] package. This makes navigation and visually parsing directories much faster, given that the file types are quickly identified by their corresponding icons.
#+begin_src emacs-lisp
(use-package all-the-icons)
#+end_src
Integration with the built-in ~dired~ package is available in the ~all-the-icons-dired~[fn:3] package.
#+begin_src emacs-lisp
(use-package all-the-icons-dired
:hook (dired-mode . all-the-icons-dired-mode))
#+end_src
** Emojis
It's finally here, first class support for Emojis in Emacs via the ~emacs-emojify~[fn:4] package. Have we finally gone too far?
#+begin_src emacs-lisp
(use-package emojify
:when (window-system)
:hook (after-init . global-emojify-mode))
#+end_src
** Scrolling
Emacs' default scrolling behaviour is annoying. The sudden half-page jumps and the variable scroll-speed can be fixed with a few simple commands.
#+begin_src emacs-lisp
(setq scroll-conservatively 101 ;; Values >= 100 fix page jumping.
mouse-wheel-scroll-amount '(3 ((shift) . 3)) ;; Control the number of lines per jump.
mouse-wheel-progressive-speed t ;; Accelerate scrolling with the mouse wheel.
mouse-wheel-follow-mouse t) ;; Scroll the window under the mouse.
#+end_src
** Ligatures
Enable ~firacode~[fn:1] font ligatures with the ~fira-code-mode~[fn:5] package. Only perform this action when ~firacode~[fn:1] is the current font, and Emacs isn't running on the TTY.
#+begin_src emacs-lisp
(use-package fira-code-mode
:when (and (window-system)
(equal dotfiles/font "Fira Code"))
:hook (prog-mode org-mode))
#+end_src
** Parenthesis
Colourize nested parenthesis with ~rainbow-delimeters~[fn:4], a mandatory life-jacked to keep you from drowning in the sea of them in Lisp.
#+begin_src emacs-lisp
(use-package rainbow-delimiters
:hook (prog-mode . rainbow-delimiters-mode))
#+end_src
** Text scaling
Define a transient keybinding for scaling the text. One caveat to this, it only works when Emacs is running as a GUI application, and has no effect in the terminal.
#+begin_src emacs-lisp
(defhydra hydra-text-scale (:timeout 4)
"Scale"
("j" text-scale-increase "Increase")
("k" text-scale-decrease "Decrease")
("f" nil "Finished" :exit t))
#+end_src
* Shortcuts
Scale the text inside of buffers using the custom transient binding, behind =SPC t f=:
+ Increase with =j=
+ Decrease with =k=
+ Finish with =f=
#+begin_src emacs-lisp
(dotfiles/leader
"tf" '(hydra-text-scale/body :which-key "Font"))
#+end_src
* Footnotes
[fn:1] https://github.com/tonsky/FiraCode
[fn:2] [[https://github.com/domtronn/all-the-icons.el]]
[fn:3] https://github.com/jtbm37/all-the-icons-dired
[fn:4] https://github.com/Fanael/rainbow-delimiters
[fn:5] https://github.com/jming422/fira-code-mode

75
modules/go.org

@ -1,75 +0,0 @@
#+TITLE: Go
#+AUTHOR: Christopher James Hayward
#+EMAIL: chris@chrishayward.xyz
#+PROPERTY: header-args:emacs-lisp :tangle go.el :comments org
#+PROPERTY: header-args:shell :tangle no
#+PROPERTY: header-args :results silent :eval no-export :comments org
#+OPTIONS: num:nil toc:nil todo:nil tasks:nil tags:nil
#+OPTIONS: skip:nil author:nil email:nil creator:nil timestamp:nil
Go is an open source programming language that makes it easy to build simple, reliable, and efficient software[fn:1]
* Setup
Install ~golang~[fn:1] on your system, and configure your environment prior to loading this module.
#+begin_src shell
RUN apt install -y golang
#+end_src
** Language server
Get started by installing the ~gopls~[fn:2] language server.
#+begin_src shell
GO111MODULE=on go get golang.org/x/tools/gopls@latest
#+end_src
** Setup the environment
Make some modifications to the environment. Set the =$GOPATH= variable prior to loading, allowing modification of the default value. Include the =bin= subdirectory of the =$GOPATH= in the =$PATH= variable, adding compiled golang applications to the system path.
#+begin_src emacs-lisp
(setenv "GOPATH" (concat (getenv "HOME") "/.go/"))
(setenv "PATH" (concat (getenv "GOPATH") "bin:" (getenv "PATH")))
#+end_src
* Config
Use the ~go-mode~[fn:3] package for integration with ~lsp-mode~, manually setting the path to ~gopls~[fn:2] before loading.
#+begin_src emacs-lisp
(use-package go-mode
:hook (go-mode . lsp)
:custom (lsp-go-gopls-server-path "~/.go/bin/gopls"))
#+end_src
** Before save hooks
Apply some custom behaviour when saving ~golang~[fn:1] buffers. Format and organize the imports before saving.
#+begin_src emacs-lisp
(defun dotfiles/go-hook ()
(add-hook 'before-save-hook #'lsp-format-buffer t t)
(add-hook 'before-save-hook #'lsp-organize-imports t t))
(add-hook 'go-mode-hook #'dotfiles/go-hook)
#+end_src
** Babel structure templates
Configure the ~babel~ engine to support ~golang~[fn:1] source blocks.
#+begin_src emacs-lisp
(add-to-list 'org-structure-template-alist '("go" . "src go"))
#+end_src
* Footnotes
[fn:1] https://golang.org
[fn:2] https://pkg.go.dev/golang.org/x/tools/gopls
[fn:3] https://emacswiki.org/emacs/GoMode

68
modules/gpg.org

@ -1,68 +0,0 @@
#+TITLE: GPG
#+AUTHOR: Christopher James Hayward
#+EMAIL: chris@chrishayward.xyz
#+PROPERTY: header-args:emacs-lisp :tangle gpg.el :comments org
#+PROPERTY: header-args:shell :tangle no
#+PROPERTY: header-args :results silent :eval no-export :comments org
#+OPTIONS: num:nil toc:nil todo:nil tasks:nil tags:nil
#+OPTIONS: skip:nil author:nil email:nil creator:nil timestamp:nil
Handle GPG[fn:1] pinentry within Emacs.
* Setup
:PROPERTIES:
:header-args: :tangle ../config/gpg-agent.conf
:END:
When the ~gpg-agent~[fn:1] loads it will read the configuration at =~/.gnupg/gpg-agent.conf=. Override the default settings to allow Emacs to function as the Pinentry application.
#+begin_src conf
allow-emacs-pinentry
allow-loopback-pinentry
#+end_src
You may need to restart the ~gpg-agent~[fn:1] to load the configuration without rebooting.
#+begin_src shell :tangle nil
gpgconf --reload gpg-agent
#+end_src
* Config
Create the symbolic link to the configuration file.
#+begin_src emacs-lisp
(dotfiles/symlink "~/.emacs.d/config/gpg-agent.conf"
"~/.gnupg/gpg-agent.conf")
#+end_src
With the ~pinentry~[fn:2] package for Emacs prompts will now appear in the minibuffer. Increase the minimum prime bit size to increase performance during symmetric encryption.
#+begin_src emacs-lisp
(use-package pinentry
:custom (epa-file-select-keys 2)
(gnutls-min-prime-bits 4096)
(epa-pinentry-mode 'loopback)
(epa-file-encrypt-to dotfiles/public-key)
(epa-file-cache-passphrase-for-symmetric-encryption t)
:config (pinentry-start))
#+end_src
** Including agenda files
Override ~org-agenda-file-regexp~ to include =.org.gpg= files.
#+begin_src emacs-lisp
(unless (string-match-p "\\.gpg" org-agenda-file-regexp)
(setq org-agenda-file-regexp
(replace-regexp-in-string "\\\\\\.org" "\\\\.org\\\\(\\\\.gpg\\\\)?"
org-agenda-file-regexp)))
#+end_src
* Footnotes
[fn:1] https://gnupg.org
[fn:2] https://elpa.gnu.org/packages/pinentry.html

30
modules/grammar.org

@ -1,30 +0,0 @@
#+TITLE: Grammar
#+AUTHOR: Christopher James Hayward
#+EMAIL: chris@chrishayward.xyz
#+PROPERTY: header-args:emacs-lisp :tangle grammar.el :comments org
#+PROPERTY: header-args :results silent :eval no-export :comments org
#+OPTIONS: num:nil toc:nil todo:nil tasks:nil tags:nil
#+OPTIONS: skip:nil author:nil email:nil creator:nil timestamp:nil
Real time checking and one-shot methods to check and correct common grammatical errors.
* Config
Use ~writegood-mode~ to find common writing problems such as cliches, and poor wording. Grammarly for the peons!
#+begin_src emacs-lisp
(use-package writegood-mode
:after org
:config (writegood-mode))
#+end_src
* Shortcuts
Toggle ~writegood-mode~ with =SPC t w=:
#+begin_src emacs-lisp
(dotfiles/leader
"tw" '(writegood-mode :which-key "Grammar"))
#+end_src

100
modules/hugo.org

@ -1,100 +0,0 @@
#+TITLE: Hugo
#+AUTHOR: Christopher James Hayward
#+EMAIL: chris@chrishayward.xyz
#+PROPERTY: header-args:emacs-lisp :tangle hugo.el :comments org
#+PROPERTY: header-args :results silent :eval no-export :comments org
#+OPTIONS: num:nil toc:nil todo:nil tasks:nil tags:nil
#+OPTIONS: skip:nil author:nil email:nil creator:nil timestamp:nil
Create entire websites with Emacs.
* Setup
Download and install ~hugo~[fn:1] on your system before loading the module:
#+begin_src shell
RUN apt install -y hugo
#+end_src
* Config
It's possible to export ~org-mode~ into ~hugo~[fn:1] specific markdown[fn:2] using the ~ox-hugo~[fn:3] package. I have my setup configured for one-post-per-file, despite it not being the suggested method. The option will appear in the default export menu inside of an ~org-mode~ buffer, accessible by pressing =C-c C-e=.
#+begin_src emacs-lisp
(use-package ox-hugo
:after ox)
#+end_src
* Shortcuts
Create capture templates for creating new blog posts, and creating publicly shared notes on various topics, and other peoples published works.
** Posts
I post nonsense on my personal blog, available here[fn:4]. This template makes sure the file ends up going to the right location, with the configuration pre-applied.
#+begin_src emacs-lisp
(with-eval-after-load 'org-roam
(add-to-list 'org-roam-capture-templates
'("p" "Post" plain (function org-roam-capture--get-point)
"%?"
:file-name "docs/posts/${slug}"
:unnarrowed t
:head
"
,#+TITLE: ${title}
,#+AUTHOR: Christopher James Hayward
,#+DATE: %<%Y-%m-%d>
,#+OPTIONS: num:nil todo:nil tasks:nil
,#+EXPORT_FILE_NAME: ${slug}
,#+ROAM_KEY: https://chrishayward.xyz/posts/${slug}/
,#+HUGO_BASE_DIR: ../
,#+HUGO_AUTO_SET_LASTMOD: t
,#+HUGO_SECTION: posts
,#+HUGO_DRAFT: true
")))
#+end_src
** Notes
Read my notes on various textbooks, artciles, and other un-categorized nonsense here[fn:5]. This template makes sure the file ends up going to the right location, with the configuration pre-applied.
#+begin_src emacs-lisp
(with-eval-after-load 'org-roam
(add-to-list 'org-roam-capture-templates
'("n" "Notes" plain (function org-roam-capture--get-point)
"%?"
:file-name "docs/notes/${slug}"
:unnarrowed t
:head
"
,#+TITLE: ${title}
,#+AUTHOR: Christopher James Hayward
,#+OPTIONS: num:nil todo:nil tasks:nil
,#+EXPORT_FILE_NAME: ${slug}
,#+ROAM_KEY: https://chrishayward.xyz/notes/${slug}/
,#+HUGO_BASE_DIR: ../
,#+HUGO_AUTO_SET_LASTMOD: t
,#+HUGO_SECTION: notes
,#+HUGO_DRAFT: true
")))
#+end_src
* Footnotes
[fn:1] https://gohugo.io
[fn:2] https://markdownguide.org/tools/hugo
[fn:3] https://github.com/kaushalmodi/ox-hugo
[fn:4] https://chrishayward.xyz/posts/
[fn:5] https://chrishayward.xyz/notes/

80
modules/ivy.org

@ -1,80 +0,0 @@
#+TITLE: Ivy
#+AUTHOR: Christopher James Hayward
#+EMAIL: chris@chrishayward.xyz
#+PROPERTY: header-args:emacs-lisp :tangle ivy.el :comments org
#+PROPERTY: header-args:shell :tangle no
#+PROPERTY: header-args :results silent :eval no-export :comments org
#+OPTIONS: num:nil toc:nil todo:nil tasks:nil tags:nil
#+OPTIONS: skip:nil author:nil email:nil creator:nil timestamp:nil
Bring Emacs out of the eighties.
* Config
There's a lot of occasions where Emacs asks you to input text to match a file name in a directory, or of a potential buffer selection. The family of packages ~ivy/swiper~[fn:1] work together toward this common goal of improving the default completion menu system.
#+begin_src emacs-lisp
(use-package ivy
:diminish
:config (ivy-mode 1))
#+end_src
** Replacements
Include ~counsel~[fn:2], a customized set of commands to replace the built-in completion buffers. This will provide an experience similar to what you've maybe experienced on ~doom~ or ~spacemacs~.
#+begin_src emacs-lisp
(use-package counsel
:after ivy
:custom (counsel-linux-app-format-function #'counsel-linux-app-format-function-name-only)
:config (counsel-mode 1))
#+end_src
** Additional details
Provide more information about each item in the completion menu with ~ivy-rich~[fn:3]. This will include snippets from any available documentation, or active buffers.
#+begin_src emacs-lisp
(use-package ivy-rich
:after counsel
:init (ivy-rich-mode 1))
#+end_src
** Popup selection frame
Display ~ivy~[fn:1] completions in a popup buffer with the ~ivy-posframe~[fn:4] package. I prefer to use this since the menu appears in the center of my screen, stopping my from having to tilt my head to look down at the default completion menu appearing in the mini-buffer.
#+begin_src emacs-lisp
(use-package ivy-posframe
:after ivy
:when (window-system)
:custom (ivy-posframe-display-functions-alist '((t . ivy-posframe-display)))
(ivy-posframe-parameters '((parent-frame nil)))
:config (ivy-posframe-mode 1))
#+end_src
** Candidate selection sorting
Sort completion candidates based on how recently or frequently they're selected with ~prescient.el~[fn:5]. This can be helpful when using =M-x= to run commands that aren't bound to specific key-strokes.
#+begin_src emacs-lisp
(use-package ivy-prescient
:after counsel
:custom (ivy-prescient-enable-filtering nil)
:config (prescient-persist-mode 1)
(ivy-prescient-mode 1))
#+end_src
* Footnotes
[fn:1] https://github.com/abo-abo/swiper
[fn:2] https://libraries.io/emacs/counsel
[fn:3] https://github.com/Yevgnen/ivy-rich
[fn:4] https://github.com/tumashu/ivy-posframe
[fn:5] https://github.com/raxod502/prescient.el

137
modules/keys.org

@ -1,137 +0,0 @@
#+TITLE: Keys
#+AUTHOR: Christopher James Hayward
#+EMAIL: chris@chrishayward.xyz
#+PROPERTY: header-args:emacs-lisp :tangle keys.el :comments org
#+PROPERTY: header-args :results silent :eval no-export :comments org
#+OPTIONS: num:nil toc:nil todo:nil tasks:nil tags:nil
#+OPTIONS: skip:nil author:nil email:nil creator:nil timestamp:nil
Improve the keyboard experience within Emacs.
* Config
Some of the default keybindings in Emacs really do leave you wondering, for example, when you want to exit a prompt you have to use =C-g=. Offer =ESC= as an alternative to quit (most) prompts, which I have muscle memory for already from literally every program created since 1990.
#+begin_src emacs-lisp
(global-set-key (kbd "<escape>") 'keyboard-escape-quit)
#+end_src
** Hints
Since Emacs is keyboard driven software, there are a lot of keybindings. Sometimes it's useful to start pressing well-known key combinations, and view the available completions. This behaviour is implemented in the third-party package ~which-key~[fn:1]. It displays the current incomplete keybinding input in a mini-buffer. It also works in the other direction, showing the corresponding keybindings for each command when you run =M-x=.
#+begin_src emacs-lisp
(use-package which-key
:diminish which-key-mode
:custom (which-key-idle-delay dotfiles/idle)
:config (which-key-mode))
#+end_src
** Leader
If like myself, you started using Emacs using a framework such as ~doom~[fn:2] or ~spacemacs~[fn:3], you probably have a considerable amount of muscle memory developed for using =SPC= as a leader key. In both of the previously mentioned frameworks, the package ~general.el~[fn:4] is used to implement this behaviour. It's a major improvement to the default way of creating custom keybindings in Emacs.
#+begin_src emacs-lisp
(use-package general
:config
(general-create-definer dotfiles/leader
:states '(normal motion)
:keymaps 'override
:prefix dotfiles/leader-key
:global-prefix dotfiles/leader-key-global))
#+end_src
** Transient
Create transient keybindings with a shared prefix through ~hydra~[fn:5]. This is also used by a number of third-party packages as a completion system. An implementation example is used to scale the font size.
#+begin_src emacs-lisp
(use-package hydra
:defer t)
#+end_src
* Shortcuts
Implement some shortcut bindings, with a significant portion of them cherry picked from ~doom~[fn:2]:
+ Close buffers with =SPC c=
+ Find files with =SPC . (period)=
+ Switch buffers with =SPC , (comma)=
+ Kill buffers with =SPC / (slash)=
#+begin_src emacs-lisp
(dotfiles/leader
"." '(find-file :which-key "Files")
"," '(switch-to-buffer :which-key "Buffers")
"c" '(kill-buffer-and-window :which-key "Close"))
#+end_src
** Quitting Emacs
Customize the behaviour of exiting emacs, with keybindings behind =SPC q=:
+ Save and quit =q=
+ Quit without saving =w=
+ Exit the Frame (daemon) =f=
#+begin_src emacs-lisp
(dotfiles/leader
"q" '(:ignore t :which-key "Quit")
"qq" '(save-buffers-kill-emacs :which-key "Save")
"qw" '(kill-emacs :which-key "Now")
"qf" '(delete-frame :which-key "Frame"))
#+end_src
** Managing windows
Screen space is divided into Frames inside of Emacs, manage them behind =SPC w=:
+ Swap with =w=
+ Close with =c=
+ Delete with =d=
+ Move with =h,j,k,l=
+ Split with =s - <motion>=
#+begin_src emacs-lisp
(dotfiles/leader
"w" '(:ignore t :which-key "Window")
"ww" '(window-swap-states :which-key "Swap")
"wc" '(delete-window :which-key "Close")
"wh" '(windmove-left :which-key "Left")
"wj" '(windmove-down :which-key "Down")
"wk" '(windmove-up :which-key "Up")
"wl" '(windmove-right :which-key "Right")
"ws" '(:ignore t :which-key "Split")
"wsj" '(split-window-below :which-key "Down")
"wsl" '(split-window-right :which-key "Right"))
#+end_src
** Helper Functions
Use the built-in ~describe-*~ functionality of Emacs to quickly access documentation for packages, variables, and functions. Run helper functions with =SPC h=:
+ Packages =p=
+ Variables =v=
+ Functions =f=
#+begin_src emacs-lisp
(dotfiles/leader
"h" '(:ignore t :which-key "Help")
"hp" '(describe-package :which-key "Package")
"hv" '(describe-variable :which-key "Variable")
"hf" '(describe-function :which-key "Function"))
#+end_src
* Footnotes
[fn:1] https://github.com/justbur/emacs-which-key/
[fn:2] https://github.com/hlissner/doom-emacs/
[fn:3] https://spacemacs.org
[fn:4] https://github.com/noctuid/general.el
[fn:5] https://github.com/abo-abo/hydra

76
modules/lsp.org

@ -1,76 +0,0 @@
#+TITLE: Language Server Protocol
#+AUTHOR: Christopher James Hayward
#+EMAIL: chris@chrishayward.xyz
#+PROPERTY: header-args:emacs-lisp :tangle lsp.el :comments org
#+PROPERTY: header-args:shell :tangle no
#+PROPERTY: header-args :results silent :eval no-export :comments org
#+OPTIONS: num:nil toc:nil todo:nil tasks:nil tags:nil
#+OPTIONS: skip:nil author:nil email:nil creator:nil timestamp:nil
The Language Server Protocol (LSP) defines the protocol used between an editor, or IDE, and a language server that provides language features like auto-complete, go-to-definition, find-all-references, etc[fn:1]
* Config
Support for the Language Server Protocol[fn:1] is available through the ~lsp-mode~[fn:2] package. Configure an immutable delay of =.5= to ensure it doesn't attack the current language server and overload it with requests.
#+begin_src emacs-lisp
(use-package lsp-mode
:commands (lsp lsp-deferred)
:custom (lsp-idle-delay 0.5)
(lsp-prefer-flymake t))
#+end_src
** Code snippets
Download ~yasnippet~[fn:4], used by a number of ~lsp-mode~[fn:2] extensions to provide smart completion functionality.
#+begin_src emacs-lisp
(use-package yasnippet
:ensure t)
#+end_src
** UI integration
Download ~lsp-ui~[fn:3] to provide user interface improvements for ~lsp-mode~[fn:2] over the defaults.
#+begin_src emacs-lisp
(use-package lsp-ui
:after lsp
:custom (lsp-ui-doc-position 'at-point)
(lsp-ui-doc-delay 0.500))
#+end_src
** Code completion
Text completion provided by ~company~[fn:5], AKA Complete Anything. Make sure it's integrated with ~lsp-mode~[fn:2] to provide completion candidates through the Language Server Protocol[fn:1].
#+begin_src emacs-lisp
(use-package company
:after lsp)
#+end_src
Specify the repository for ~company-lsp~ using straight to make sure we're getting the most recent version from GitHub, instead of the typically outdated versions in the Emacs package repositories.
#+begin_src emacs-lisp
(use-package company-lsp
:after (lsp company)
:custom (company-lsp-async t)
(company-backend 'company-lsp)
:straight (company-lsp :type git
:host github
:repo "tigersoldier/company-lsp"))
#+end_src
* Footnotes
[fn:1] https://microsoft.github.io/language-server-protocol/
[fn:2] https://emacs-lsp.github.io/lsp-mode/
[fn:3] https://emacs-lsp.github.io/lsp-ui/
[fn:4] https://github.com/joaotavora/yasnippet
[fn:5] https://company-mode.github.io/

62
modules/magit.org

@ -1,62 +0,0 @@
#+TITLE: Magit
#+AUTHOR: Christopher James Hayward
#+EMAIL: chris@chrishayward.xyz
#+PROPERTY: header-args:emacs-lisp :tangle magit.el :comments org
#+PROPERTY: header-args :results silent :eval no-export :comments org
#+OPTIONS: num:nil toc:nil todo:nil tasks:nil tags:nil
#+OPTIONS: skip:nil author:nil email:nil creator:nil timestamp:nil
Handle all of the git interactions inside of Emacs.
* Setup
Deploy the global configuration file for ~git~[fn:1], by default it reads from =$HOME/.gitconfig=.
#+begin_src emacs-lisp
(dotfiles/symlink "~/.emacs.d/config/git"
"~/.gitconfig")
#+end_src
* Config
Another hallmark feature of Emacs is ~magit~[fn:2]. It's a complete git porcelain inside of Emacs. The developer has stressed that it's most unfortunate name was meant to be pronounced like *magic* but with *git*. Despire his best efforts a lot of people have taken to pronouncing it *maggot*, which keeps him awake at night (probably).
#+begin_src emacs-lisp
(use-package magit
:commands magit-status
:custom (magit-display-buffer-function
#'magit-display-buffer-same-window-except-diff-v1))
#+end_src
** Forge integration
It's possible to interact with forges from Github / Gitlab using ~forge~[fn:3]. It requires the respective =$TOKEN= to be configured, or an alternative form of authentication. This enables working with pull-requests, code-reviews, and issues from inside of Emacs.
#+begin_src emacs-lisp
(use-package forge
:after magit)
#+end_src
* Shortcuts
Interact with ~magit~[fn:2] behind =SPC g=:
+ Clone with =c=
+ Status with =g=
#+begin_src emacs-lisp
(dotfiles/leader
"g" '(:ignore t :which-key "Magit")
"gc" '(magit-clone :which-key "Clone")
"gg" '(magit-status :which-key "Status"))
#+end_src
* Footnotes
[fn:1] https://git-scm.com
[fn:2] https://github.com/magit/magit
[fn:3] https://github.com/magit/forge

19
modules/modeline.org

@ -1,19 +0,0 @@
#+TITLE: Modeline
#+AUTHOR: Christopher James Hayward
#+EMAIL: chris@chrishayward.xyz
Extend the usability of the Emacs modeline.
* Config
Implement and elegant and modern status bar, fully customizable and compatible with our themes with the ~doom-modeline~[fn:1] package.
#+begin_src emacs-lisp
(use-package doom-modeline
:custom (doom-modeline-height 16)
:config (doom-modeline-mode 1))
#+end_src
* Footnotes
[fn:1] https://github.com/seagle0128/doom-modeline

150
modules/mu4e.org

@ -1,150 +0,0 @@
#+TITLE: Mu4e
#+AUTHOR: Christopher James Hayward
#+EMAIL: chris@chrishayward.xyz
#+PROPERTY: header-args:emacs-lisp :tangle mu4e.el :comments org
#+PROPERTY: header-args:shell :tangle no
#+PROPERTY: header-args :results silent :eval no-export :comments org
#+OPTIONS: num:nil toc:nil todo:nil tasks:nil tags:nil
#+OPTIONS: skip:nil author:nil email:nil creator:nil timestamp:nil
Plain-text email inside of Emacs.
* Setup
Make sure the following dependencies are installed on your system before loading the module. I would recommend against using any distributions pre-packaged version of ~mu4e~[fn:1], and instead build it yourself which I detail in this post[fn:2]:
#+begin_src shell
RUN apt install -y isync libgmime-3.0-dev libxapian-dev
#+end_src
** Setting up mbsync
:PROPERTIES:
:header-args: :tangle ../config/mbsyncrc :comments org
:END:
The program that actually synchronizes the emails with the server is ~mbsync~[fn:3]. Create the configuration file, this is for my personal mail server[fn:4], which I host myself, so make sure you write your own.
#+begin_src conf
IMAPStore xyz-remote
Host mail.chrishayward.xyz
User chris@chrishayward.xyz
PassCmd "pass chrishayward.xyz/chris"
SSLType IMAPS
MaildirStore xyz-local
Path ~/.cache/mail/
Inbox ~/.cache/mail/inbox
SubFolders Verbatim
Channel xyz
Master :xyz-remote:
Slave :xyz-local:
Patterns * !Archives
Create Both
Expunge Both
SyncState *
#+end_src
** Create symbolic links
The system typically expects to find this file at =$HOME/.mbsyncrc=, but you may also specify a custom path if launching the command using arguments. I chose to symlink the default location to my repository.
#+begin_src emacs-lisp
(dotfiles/symlink "~/.emacs.d/config/mbsyncrc"
"~/.mbsyncrc")
#+end_src
This repository also contains my personal encrypted auth info, this is required by ~mbsync~[fn:3] to sign all of the outbound messages.
#+begin_src emacs-lisp
(dotfiles/symlink "~/.emacs.d/config/authinfo.gpg"
"~/.authinfo.gpg")
#+end_src
** First time indexing
Before you can use ~mu4e~[fn:1] inside of Emacs, you need to synchronize the mail database, and index it using ~mu~[fn:5], the library used by ~mu4e~[fn:1] under the hood. Execute these commands in your terminal before loading the module, after that you can do everything inside of Emacs:
#+begin_src shell
RUN mbsync -a
RUN mu init --maildir="~/.cache/mail" --my-address="chris@chrishayward.xyz"
RUN mu index
#+end_src
* Config
After syncing and indexing, the mail is ready for Emacs. Include ~mu4e~[fn:1] in the configuration by adding the custom built version to the load path, and configure the mail account.
+ Update every 5 minutes
+ Configure mail account(s)
+ Scale text for all devices
+ Sign outbound mail with GPG key
#+begin_src emacs-lisp
(use-package mu4e
:load-path "~/.local/source/mu/mu4e/"
:custom (mu4e-maildir "~/.cache/mail")
(mu4e-update-interval (* 5 60))
(mu4e-get-mail-command "mbsync -a")
(mu4e-compose-format-flowed t)
(mu4e-change-filenames-when-moving t)
(message-send-mail-function 'smtpmail-send-it)
(mml-secure-openpgp-signers '("37AB1CB72B741E478CA026D43025DCBD46F81C0F"))
(mu4e-compose-signature (concat "Chris Hayward\n"
"https://chrishayward.xyz\n"))
:config
(add-hook 'message-send-hook 'mml-secure-message-sign-pgpmime)
(setq mu4e-contexts
(list
;; Main
;; chris@chrishayward.xyz
(make-mu4e-context
:name "Main"
:match-func
(lambda (msg)
(when msg
(string-prefix-p "/Main" (mu4e-message-field msg :maildir))))
:vars
'((user-full-name . "Christopher James Hayward")
(user-mail-address . "chris@chrishayward.xyz")
(smtpmail-smtp-server . "mail.chrishayward.xyz")
(smtpmail-smtp-service . 587)
(smtpmail-stream-type . starttls))))))
#+end_src
** Desktop notifications
Receive desktop notifications when new mail arrives with the ~mu4e-alert~[fn:6] package.
#+begin_src emacs-lisp
(use-package mu4e-alert
:after mu4e
:custom (mu4e-alert-set-default-style 'libnotify)
:config (mu4e-alert-enable-notifications)
(mu4e-alert-enable-mode-line-display))
#+end_src
* Shortcuts
Open the ~mu4e~[fn:1] dashboard with =SPC m=.
#+begin_src emacs-lisp
(dotfiles/leader
"m" '(mu4e :which-key "Mu4e"))
#+end_src
* Footnotes
[fn:1] https://emacswiki.org/emacs/mu4e
[fn:2] https://chrishayward.xyz/posts/installing-mu-mu4e-from-source/
[fn:3] https://isync.sourceforge.io
[fn:4] mailto:chris@chrishayward.xyz
[fn:5] https://codewith.mu/en/download
[fn:6] https://github.com/iqbalansari/mu4e-alert

27
modules/nix.org

@ -1,27 +0,0 @@
#+TITLE: Nix
#+AUTHOR: Christopher James Hayward
#+EMAIL: chris@chrishayward.xyz
#+PROPERTY: header-args:emacs-lisp :tangle nix.el :comments org
#+PROPERTY: header-args :results silent :eval no-export :comments org
#+OPTIONS: num:nil toc:nil todo:nil tasks: nil tags:nil
#+OPTIONS: skip:nil author:nil emacs:nil creator:nil timestamp:nil
* Setup
*Nix*[fn:1] is a package manager for Linux that uses functional configuration language to build reproducible package deployments. *NixOS*[fn:2] is an extension of the Nix package manager to the entire operating system.
* Config
Download and install ~nix-mode~ for working with *Nix* language buffers.
#+begin_src emacs-lisp
(use-package nix-mode)
#+end_src
* Footnotes
[fn:1] https://nixos.org
[fn:2] https://nixos.org

160
modules/org.org

@ -1,160 +0,0 @@
#+TITLE: Org
#+AUTHOR: Christopher James Hayward
#+EMAIL: chris@chrishayward.xyz
#+PROPERTY: header-args:emacs-lisp :tangle org.el :comments org
#+PROPERTY: header-args :results silent :eval no-export :comments org
#+OPTIONS: num:nil toc:nil todo:nil tasks:nil tags:nil
#+OPTIONS: skip:nil author:nil email:nil creator:nil timestamp:nil
Organize your plain-life in plain-text. The hallmark feature of Emacs, ~org-mode~[fn:1] is the king of markup languages. It has rich feature support for project management, scheduling, development, and writing. It's hard to convey everything within its capabilities.
* Setup
Define a custom hook when ~org-mode~[fn:1] is enabled to customize the experience:
+ Enable ~org-indent-mode~ to indent and align text with the parent heading
+ Enable ~visual-line-mode~ to allow text to overflow and wrap to the next visual line
+ Enable ~variable-pitch-mode~ to support multiple font-pitches and monospaced fonts
#+begin_src emacs-lisp
(defun dotfiles/org-mode-hook ()
(org-indent-mode) ;; Indent and align text.
(visual-line-mode 1) ;; Allow text to overflow line.
(variable-pitch-mode 1)) ;; Enable monospaced fonts.
#+end_src
* Config
Force ~straight~ to ignore the local version of ~org-mode~[fn:1], instead downloading the most recent version available.
#+begin_src emacs-lisp
(straight-use-package '(org :local-repo nil))
#+end_src
Setup the default babel languages and structure templates, and apply customizations:
+ Setup ~org-mode-hook~ with our custom hook
+ Setup ~org-ellipsis~ to show headlines with hidden contents
+ Setup ~org-log-*~ for event logging
+ Setup ~org-src-*~ for source blocks
+ Setup ~org-todo-keyword~ sequence
#+begin_src emacs-lisp
(use-package org
:hook (org-mode . dotfiles/org-mode-hook)
:custom (org-ellipsis " ▾")
(org-log-done 'time)
(org-log-into-drawer t)
(org-return-follows-link t)
(org-image-actual-width nil)
(org-directory dotfiles/home)
(org-src-fontify-natively t)
(org-src-tab-acts-natively t)
(org-src-preserve-indentation t)
(org-confirm-babel-evaluate nil)
(org-todo-keywords '((sequence "TODO" "START" "WAIT" "DONE")))
:config (require 'org-tempo) ;; Required for structure templates.
(add-to-list 'org-structure-template-alist '("s" . "src"))
(add-to-list 'org-structure-template-alist '("q" . "quote"))
(add-to-list 'org-structure-template-alist '("e" . "example"))
(add-to-list 'org-structure-template-alist '("sh" . "src shell"))
(add-to-list 'org-structure-template-alist '("el" . "src emacs-lisp"))
(org-babel-do-load-languages 'org-babel-load-languages '((shell . t)
(emacs-lisp . t))))
#+end_src
** Pomodoro
Adds support for the Pomodoro workflow in Emacs through the ~org-pomodoro~[fn:4] package. Some workflows benefit from thje option to work a few minutes of *overtime* to finish a task before taking a break. With this workflow, a break notification is sent at the end of the pomodoro timer, but the break starts when calling =M-x org-pomodoro=.
#+begin_src emacs-lisp
(use-package org-pomodoro
:after org
:custom (org-pomodoro-manual-break t) ;; Enable the 'overtime' workflow.
(org-pomodoro-keep-killed-time t)) ;; Track abandoned timers.
#+end_src
** Flashcards
Create study flashcards using ~org-drill~[fn:2], an extension for ~org-mode~. It uses a spaced repititon algorithm to conduct interactive drill sesslions using ~org-mode~ buffers as sources of facts to be memorized. Each drill can be restricted to topics in the current buffer, one of several, all agenda files, or a single topic across all buffers.
#+begin_src emacs-lisp
(use-package org-drill
:after org)
#+end_src
** Headline stars
Make the headline stars a bit more *super* with ~org-superstar-mode~[fn:3]. Only enable this inside of a window system, as the effect can be distracting on the TTY.
#+begin_src emacs-lisp
(use-package org-superstar
:when (window-system)
:after org
:hook (org-mode . org-superstar-mode))
#+end_src
* Methods
Define some custom methods for use in the rest of the configuration.
** Tangle directory
Build all of the ~org~ files within a given directory, recursively. This is used in CI.
#+begin_src emacs-lisp
(defun dotfiles/tangle (dir)
"Recursively tangle the Org files within a directory."
(interactive)
(let ((org-files (directory-files-recursively dir "org")))
(dolist (f org-files)
(org-babel-tangle-file f))))
#+end_src
** Force symbolic links
Function that takes in a system and configuration file path, checks to see if the system file doesn't exist, or doesn't point to the configuration file, deleting it for the latter, then creating a symbolic link to the configuration file in place.
#+begin_src emacs-lisp
(defun dotfiles/symlink (src tgt)
"Forces a symlink from `src' to `tgt'."
(interactive)
(let ((sys-file (expand-file-name tgt))
(dot-file (expand-file-name src)))
(when (or (not (file-exists-p sys-file))
(not (equal (file-symlink-p sys-file) dot-file)))
(delete-file sys-file)
(make-symbolic-link dot-file sys-file))))
#+end_src
* Shortcuts
Place ~org-mode~[fn:1] extension bindings behind =SPC o=.
+ Drill with =d=
+ Drill with =d=
+ Resume with =r=
+ Pomodoro with =p=
#+begin_src emacs-lisp
(dotfiles/leader
"o" '(:ignore t :which-key "Org")
"od" '(:ignore t :which-key "Drill")
"odd" '(org-drill :which-key "Drill")
"odc" '(org-drill-cram :which-key "Cram")
"odr" '(org-drill-resume :which-key "Resume")
"op" '(org-pomodoro :which-key "Pomodoro"))
#+end_src
* Footnotes
[fn:1] https://orgmode.org
[fn:2] https://orgmode.org/worg/org-contrib/org-drill.html
[fn:3] https://github.com/integral-dw/org-superstar-mode
[fn:4] https://github.com/marcinkoziej/org-pomodoro

51
modules/pass.org

@ -1,51 +0,0 @@
#+TITLE: Pass
#+AUTHOR: Christopher James Hayward
#+EMAIL: chris@chrishayward.xyz
#+PROPERTY: header-args:emacs-lisp :tangle pass.el :comments org
#+PROPERTY: header-args:shell :tangle no
#+PROPERTY: header-args :results silent :eval no-export :comments org
#+OPTIONS: num:nil toc:nil todo:nil tasks:nil tags:nil
#+OPTIONS: skip:nil author:nil email:nil creator:nil timestamp:nil
Password management inside of Emacs.
* Setup
Install ~pass~[fn:1] on the system before loading the module.
#+begin_src shell
RUN apt install -y pass
#+end_src
* Config
Encrypted passwords are stored inside files, in a file structure providing easy commands for generating, modifying, and copying passwords. ~password-store.el~[fn:2] provides a wrapper for the functionality within Emacs.
#+begin_src emacs-lisp
(use-package password-store
:custom (password-store-dir dotfiles/passwords))
#+end_src
* Shortcuts
Configure keybindings behind =SPC p=:
+ Copy with =p=
+ Rename with =r=
+ Generate with =g=
#+begin_src emacs-lisp
(dotfiles/leader
"p" '(:ignore t :which-key "Passwords")
"pp" '(password-store-copy :which-key "Copy")
"pr" '(password-store-rename :which-key "Rename")
"pg" '(password-store-generate :which-key "Generate"))
#+end_src
* Footnotes
[fn:1] https://passwordstore.org
[fn:2] https://github.com/NicolasPetton/pass

136
modules/projects.org

@ -1,136 +0,0 @@
#+TITLE: Projects
#+AUTHOR: Christopher James Hayward
#+EMAIL: chris@chrishayward.xyz
#+PROPERTY: header-args:emacs-lisp :tangle projects.el :comments org
#+PROPERTY: header-args:shell :tangle no
#+PROPERTY: header-args :results silent :eval no-export :comments org
#+OPTIONS: num:nil toc:nil todo:nil tasks:nil tags:nil
#+OPTIONS: skip:nil author:nil email:nil creator:nil timestamp:nil
#+ATTR_ORG: :width 420px
#+ATTR_HTML: :width 420px
#+ATTR_LATEX: :width 420px
[[../docs/images/2021-02-13-example-ccls.gif]]
An *IDE*[fn:1] like experience or better can be achieved within Emacs using two *Microsoft*[fn:2] open-source initiatives:
+ *Debug Adapter Protocol*[fn:3]
+ *Language Server Protocol*[fn:4]
* Code snippets
#+begin_src emacs-lisp
(use-package yasnippet
:ensure t)
#+end_src
* Debug adapters
*Dap mode*[fn:5] provides support for the *Debug Adapter Protocol*[fn:3] inside of Emacs.
#+begin_src emacs-lisp
(use-package dap-mode
:commands (dap-debug))
#+end_src
* Language servers
Support for the *Language Server Protocol*[fn:4] is added to Emacs through the *Lsp mode*[fn:6] package.
#+begin_src emacs-lisp
(use-package lsp-mode
:commands (lsp lsp-deferred)
:custom (lsp-idle-delay (* 5 dotfiles/idle))
(lsp-prefer-flymake t))
#+end_src
** UI integration
*Lsp ui*[fn:7] provides user interface improvements for *Lsp mode*[fn:6].
#+begin_src emacs-lisp
(use-package lsp-ui
:after lsp
:custom (lsp-ui-doc-position 'at-point)
(lsp-ui-doc-delay 0.500))
#+end_src
** Code completion
Text completion via *Company*[fn:8] =AKA= *Complete Anything*.
#+begin_src emacs-lisp
(use-package company
:after lsp)
#+end_src
Integrate with *Lsp mode*[fn:6] to provide completion candidates through the *Language Server Protocol*[fn:4].
+ Specify the repository
+ Use asynchronous completion
#+begin_src emacs-lisp
(use-package company-lsp
:after (lsp company)
:custom (company-lsp-async t)
(company-backend 'company-lsp)
:straight (company-lsp :type git
:host github
:repo "tigersoldier/company-lsp"))
#+end_src
* Docker containers
Manage *Docker*[fn:9] containers with *Docker.el*[fn:10].
#+begin_src emacs-lisp
(use-package docker
:commands (docker))
#+end_src
Open the container management screen with =SPC k=.
#+begin_src emacs-lisp
(dotfiles/leader
"k" '(docker :which-key "Docker"))
#+end_src
* Project management
Configure *Projectile*[fn:11], a project interaction library for Emacs. It provides a nice set of features for operating on a project level without introducing external dependencies.
#+begin_src emacs-lisp
(use-package projectile
:custom (projectile-project-search-path '("~/.local/source"))
:config (projectile-mode))
#+end_src
* Footnotes
[fn:1] https://en.wikipedia.org/wiki/Integrated_development_environment
[fn:2] https://en.wikipedia.org/wiki/Microsoft_and_open_source
[fn:3] https://microsoft.github.io/debug-adapter-protocol
[fn:4] https://microsoft.github.io/language-server-protocol
[fn:5] https://emacs-lsp.github.io/dap-mode/
[fn:6] https://emacs-lsp.github.io/lsp-mode/
[fn:7] https://emacs-lsp.github.io/lsp-ui/
[fn:8] https://company-mode.github.io/
[fn:9] https://docker.com
[fn:10] https://github.com/Silex/docker.el
[fn:11] https://projectile.mx
[fn:12] https://git.zx2c4.com/password-store/tree/contrib/emacs
[fn:13] https://passwordstore.org

67
modules/python.org

@ -1,67 +0,0 @@
#+TITLE: Python
#+AUTHOR: Christopher James Hayward
#+EMAIL: chris@chrishayward.xyz
#+PROPERTY: header-args:emacs-lisp :tangle python.el :comments org
#+PROPERTY: header-args:shell :tangle no
#+PROPERTY: header-args :results silent :eval no-export :comments org
#+OPTIONS: num:nil toc:nil todo:nil tasks:nil tags:nil
#+OPTIONS: skip:nil author:nil email:nil creator:nil timestamp:nil
Python is an interpreted high-level general-purpose programming language[fn:1].
* Setup
Ensure ~python3~[fn:1] is installed on the system, and the ~lsp~ and ~dap~ modules have been loaded before loading this module.
#+begin_src shell
RUN apt install -y python3 python3-pip
#+end_src
** Install the language server
Install the ~pyls~[fn:2] language server.
#+begin_src shell
RUN pip3 install --user "python-lsp-server[all]"
#+end_src
* Config
Add support for ~python3~[fn:1], including ~dap~ and ~lsp~ integration. The built-in Emacs mode ~python-mode~[fn:3] handles the rest of the integration.
#+begin_src emacs-lisp
(use-package python-mode
:hook (python-mode . lsp-deferred)
:config (require 'dap-python)
(add-to-list 'org-src-lang-modes '("python" . python))
(add-to-list 'org-structure-template-alist '("py" . "src python"))
(org-babel-do-load-languages 'org-babel-load-languages '((python . t)))
:custom (python-shell-interpreter "python3") ;; Required if "python" is not python 3.
(org-babel-python-command "python3") ;; Same as above.
(dap-python-executable "python3") ;; Same as above.
(lsp-pyls-server-command "pylsp")
(dap-python-debugger 'debugpy))
#+end_src
** Code symbols
Programming buffers can be made prettier with ~pretty-mode~[fn:4], this is complimentary to ~prettify-symbols-mode~[fn:5], a built-in package containing similar (but lacking) functionality.
#+begin_src emacs-lisp
(use-package pretty-mode
:hook (python-mode . turn-on-pretty-mode))
#+end_src
* Footnotes
[fn:1] https://python.org
[fn:2] https://pypi.org/project/python-language-server/
[fn:3] https://emacswiki.org/emacs/PythonProgrammingInEmacs
[fn:4] https://emacswiki.org/emacs/pretty-mode.el
[fn:5] https://emacswiki.org/emacs/PrettySymbol

55
modules/reveal.org

@ -1,55 +0,0 @@
#+TITLE: Reveal
#+AUTHOR: Christopher James Hayward
#+EMAIL: chris@chrishayward.xyz
#+PROPERTY: header-args:emacs-lisp :tangle reveal.el :comments org
#+PROPERTY: header-args :results silent :eval no-export
#+OPTIONS: num:nil toc:nil todo:nil tasks:nil tags:nil
#+OPTIONS: skip:nil author:nil email:nil creator:nil timestamp:nil
Create high-quality, portably presentations with ~reveal.js~[fn:1].
* Config
Integrate ~reveal.js~[fn:1] with Emacs using the ~ox-reveal~[fn:2] package. Configure it to use a CDN to produce presentations that are not dependent on any locally installed software. An important caveat here is that the paths to images must be absolute URLs. I get around this by hosting all of the images myself, meaning I can load the presentations in any web browser.
#+begin_src emacs-lisp
(use-package ox-reveal
:after ox
:custom (org-reveal-root "https://cdn.jsdelivr.net/npm/reveal.js"))
#+end_src
* Shortcuts
Add a capture tempalte for quickly creating slide presentations with the desired markup and configuration already applied.
#+begin_src emacs-lisp
(with-eval-after-load 'org-roam
(add-to-list 'org-roam-capture-templates
'("s" "Slides" plain (function org-roam-capture--get-point)
"%?"
:file-name "docs/slides/${slug}"
:unnarrowed t
:head
"
,#+TITLE: ${title}
,#+AUTHOR: Christopher James Hayward
,#+EMAIL: chris@chrishayward.xyz
,#+REVEAL_ROOT: https://cdn.jsdelivr.net/npm/reveal.js
,#+REVEAL_THEME: serif
,#+EXPORT_FILE_NAME: ${slug}
,#+OPTIONS: reveal_title_slide:nil
,#+OPTIONS: num:nil toc:nil todo:nil tasks:nil tags:nil
,#+OPTIONS: skip:nil author:nil email:nil creator:nil timestamp:nil
")))
#+end_src
* Footnotes
[fn:1] https://revealjs.com
[fn:2] https://github.com/hexmode/ox-reveal

175
modules/roam.org

@ -1,175 +0,0 @@
#+TITLE: Roam
#+AUTHOR: Christopher James Hayward
#+EMAIL: chris@chrishayward.xyz
#+PROPERTY: header-args:emacs-lisp :tangle roam.el :comments org
#+PROPERTY: header-args :results silent :eval no-export :comments org
#+OPTIONS: num:nil toc:nil todo:nil tasks:nil tags:nil
#+OPTIONS: skip:nil author:nil email:nil creator:nil timestamp:nil
Plain-text knowledge management system.
* Setup
Make sure ~sqlite~ is available on your system:
#+begin_src shell
RUN apt install sqlite
#+end_src
* Config
Configure ~org-roam~[fn:1], a plain-text knowledge management system for Emacs built on top of ~org-mode~. Here's a quick recap of the main principles:
+ Notes can be arbitrarily referened
+ Contexts created by linking topics and notes
#+begin_src emacs-lisp
(use-package org-roam
:hook (after-init . org-roam-mode) ;; Lauch roam at startup, big performance cost.
:custom (org-roam-encrypt-files t) ;; Encrypt all roam captures.
(org-roam-directory org-directory)
(org-roam-capture-templates '())
(org-roam-dailies-capture-templates '()))
#+end_src
** Files
The default behaviour of ~org-roam~[fn:1] when creating a title slug is to replace any non alpha numerical (whitespace) to ~_~. I wanted to change this to use ~_~ and have done so here in my own definition. The only substantial difference from the original definition is the character used.
+ Define a new ~title-to-slug~ function
+ Override ~org-roam-title-to-slug-function~
#+begin_src emacs-lisp
(with-eval-after-load 'org-roam
(require 'cl-lib)
(defun dotfiles/title-to-slug (title)
"Convert TITLE to a filename-suitable slug."
(cl-flet* ((nonspacing-mark-p (char)
(eq 'Mn (get-char-code-property char 'general-category)))
(strip-nonspacing-marks (s)
(apply #'string (seq-remove #'nonspacing-mark-p
(ucs-normalize-NFD-string s))))
(cl-replace (title pair)
(replace-regexp-in-string (car pair) (cdr pair) title)))
(let* ((pairs `(("[^[:alnum:][:digit:]]" . "-") ;; Convert anything not alphanumeric.
("--*" . "-") ;; Remove sequential dashes.
("^-" . "") ;; Remove starting dashes.
("-$" . ""))) ;; Remove ending dashes.
(slug (-reduce-from #'cl-replace (strip-nonspacing-marks title) pairs)))
(downcase slug))))
(setq org-roam-title-to-slug-function #'dotfiles/title-to-slug))
#+end_src
** Visualizer
Use the ~org-roam-server~[fn:2] web application to visualize the ~org-roam~[fn:1] database. It's available whenever the editor is running at http://localhost:8080.
#+begin_src emacs-lisp
(use-package org-roam-server
:after org-roam
:hook (org-roam-mode . org-roam-server-mode))
#+end_src
* Templates
Collection of capture templates for various contexts. Here is one for a generic document.
#+begin_src emacs-lisp
(with-eval-after-load 'org-roam
(add-to-list 'org-roam-capture-templates
'("d" "Default" entry (function org-roam-capture--get-point)
"%?"
:file-name "docs/${slug}"
:unnarrowed t
:head
"
,#+TITLE: ${title}
,#+AUTHOR: Christopher James Hayward
,#+EMAIL: chris@chrishayward.xyz
")))
#+end_src
** Course
Capture template for a new course. Capture with =SPC r c c=.
#+begin_src emacs-lisp
(with-eval-after-load 'org-roam
(add-to-list 'org-roam-capture-templates
'("c" "Course" plain (function org-roam-capture--get-point)
"%?"
:file-name "docs/courses/${slug}"
:unnarrowed t
:head
"
,#+TITLE: ${title}
,#+SUBTITLE:
,#+AUTHOR: Christopher James Hayward
,#+EMAIL: chris@chrishayward.xyz
,#+OPTIONS: num:nil toc:nil todo:nil tasks:nil tags:nil
,#+OPTIONS: skip:nil author:nil email:nil creator:nil timestamp:nil
")))
#+end_src
** Dailies
Use the ~daily~ note feature of ~org-roam~[fn:1] to capture daily notes. Create the default capture template with some preconfigured headers.
#+begin_src emacs-lisp
(with-eval-after-load 'org-roam
(add-to-list 'org-roam-dailies-capture-templates
'("d" "Default" entry (function org-roam-capture--get-point)
"* %?"
:file-name "docs/daily/%<%Y-%m-%d>"
:head
"
,#+TITLE: %<%Y-%m-%d>
,#+AUTHOR: Christopher James Hayward
,#+OPTIONS: num:nil toc:nil todo:nil tasks:nil tags:nil
,#+OPTIONS: skip:nil author:nil email:nil creator:nil timestamp:nil
")))
#+end_src
* Shortcuts
Configure custom keybindings for ~org-roam~[fn:1] behind =SPC r=:
+ Find with =f=
+ Insert with =i=
+ Buffer with =b=
+ Capture with =c=
#+begin_src emacs-lisp
(dotfiles/leader
"r" '(:ignore t :which-key "Roam")
"ri" '(org-roam-insert :which-key "Insert")
"rf" '(org-roam-find-file :which-key "Find")
"rc" '(org-roam-capture :which-key "Capture")
"rb" '(org-roam-buffer-toggle-display :which-key "Buffer"))
#+end_src
Place keybindings for daily notes behind =SPC r d=:
+ Date with =d=
+ Today with =t=
+ Tomorrow with =m=
+ Yesterday with =y=
#+begin_src emacs-lisp
(dotfiles/leader
"rd" '(:ignore t :which-key "Dailies")
"rdd" '(org-roam-dailies-find-date :which-key "Date")
"rdt" '(org-roam-dailies-find-today :which-key "Today")
"rdm" '(org-roam-dailies-find-tomorrow :which-key "Tomorrow")
"rdy" '(org-roam-dailies-find-yesterday :which-key "Yesterday"))
#+end_src
* Footnotes
[fn:1] https://github.com/org-roam/org-roam
[fn:2] https://github.com/org-roam/org-roam-server

98
modules/shell.org

@ -1,98 +0,0 @@
#+TITLE: Shell
#+AUTHOR: Christopher James Hayward
#+EMAIL: chris@chrishayward.xyz
#+PROPERTY: header-args:emacs-lisp :tangle shell.el :comments org
#+PROPERTY: header-args :results silent :eval no-export :comments org
#+OPTIONS: num:nil toc:nil todo:nil tasks:nil tags:nil
#+OPTIONS: skip:nil author:nil email:nil creator:nil timestamp:nil
Shell environment integration.
* Setup
:PROPERTIES:
:header-args: :tangle ../config/profile :comments org
:END:
Override the default behaviour of the Shell environment to integrate with Emacs.
** Force colours
When using Emacs on the TTY, the colours sometimes will default to 16 or 8 colours, making it look horrible. It's possible to override this behaviour on every platform by manually set the terminal type to =xterm-256color=.
#+begin_src shell
export TERM=xterm-256color
#+end_src
** Setting up the $PATH
Ensure =~/.local/bin= has been added to the ~$PATH~ environment variable, this location is used frequently to deploy local binaries.
#+begin_src shell
export PATH=$PATH:~/.local/bin
#+end_src
** Starting Emacs by default on TTY1
When launching into a new session on TTY1, if the display server is not running, run ~startx~[fn:1]. This will launch the window manager.
#+begin_src shell
if [ -z "${DISPLAY}" ] && [ "${XDG_VTNR}" -eq 1 ]; then
exec startx
fi
#+end_src
** Creating symbolic links
The system looks for the default shell profile under ~bash~[fn:2] at =~/.profile=. Creating a symbolic link from this location to our configuration will override the startup behaviour.
#+begin_src emacs-lisp
(dotfiles/symlink "~/.emacs.d/config/profile"
"~/.profile")
#+end_src
* Methods
Define methods for interaction between Emacs and the underlying shell environment.
** Run an external process
Define a method to run an external process, launching any application on a new process without interferring with Emacs.
#+begin_src emacs-lisp
(defun dotfiles/run (cmd)
"Run an external process."
(interactive (list (read-shell-command "λ ")))
(start-process-shell-command cmd nil cmd))
#+end_src
** Apply command to call process
Define a method to apply commands to the current call process, this is to avoid issues with hooks but can impact the performance of Emacs.
#+begin_src emacs-lisp
(defun dotfiles/run-in-background (cmd)
(let ((command-parts (split-string cmd "[ ]+")))
(apply #'call-process `(,(car command-parts) nil 0 nil ,@(cdr command-parts)))))
#+end_src
* Shortcuts
Place keybindings for executing shell commands behind =SPC x=:
+ Run shell commands with =x=
+ Run async shell commands with =z=
#+begin_src emacs-lisp
(dotfiles/leader
"x" '(:ignore t :which-key "Run")
"xx" '(dotfiles/run :which-key "Run")
"xz" '(async-shell-command :which-key "Async"))
#+end_src
* Footnotes
[fn:1] https://x.org
[fn:2] https://gnu.org/software/bash/

36
modules/spelling.org

@ -1,36 +0,0 @@
#+TITLE: Spelling
#+AUTHOR: Christopher James Hayward
#+EMAIL: chris@chrishayward.xyz
#+PROPERTY: header-args:emacs-lisp :tangle spelling.el :comments org
#+PROPERTY: header-args :results silent :eval no-export :comments org
#+OPTIONS: num:nil toc:nil todo:nil tasks:nil tags:nil
#+OPTIONS: skip:nil author:nil email:nil creator:nil timestamp:nil
Real time checking and one-shot methods to check and correct common spelling mistakes.
* Config
Configure ~ispell~[fn:1] as a back-end with ~flyspell~[fn:2] for real-time checking and highlighting of spelling mistakes.
#+begin_src emacs-lisp
(use-package ispell
:after org
:custom (ispell-dictionary dotfiles/lang))
#+end_src
* Shortcuts
Toggle highlighting within buffer specific contexts with =SPC t s=:
#+begin_src emacs-lisp
(dotfiles/leader
"ts" '(flyspell-buffer :which-key "Spelling"))
#+end_src
* Footnotes
[fn:1] https://gnu.org/software/ispell/
[fn:2] https://emacswiki.org/emacs/FlySpell

48
modules/themes.org

@ -1,48 +0,0 @@
#+TITLE: Themes
#+AUTHOR: Christopher James Hayward
#+EMAIL: chris@chrishayward.xyz
#+PROPERTY: header-args:emacs-lisp :tangle themes.el :comments org
#+PROPERTY: header-args:shell :tangle no
#+PROPERTY: header-args :results silent :eval no-export :comments org
#+OPTIONS: num:nil toc:nil todo:nil tasks:nil tags:nil
#+OPTIONS: skip:nil author:nil email:nil creator:nil timestamp:nil
Configure a unified look and feel across the system with modern themes.
* Setup
Easily swap between system themes using the ~lxappearance~[fn:1] tool. I tend to default to the ~arc-theme~[fn:2] as it looks really good with most themes.
#+begin_src shell
RUN apt install -y lxappearance
#+end_src
* Config
High quality and modern colour themes are provides inside of Emacs via the ~doom-themes~[fn:3] package. Some of the themes can be further configured, see the documentation for more details.
#+begin_src emacs-lisp
(use-package doom-themes
:init (load-theme 'doom-moonlight t)
:custom (doom-themes-enable-bold t)
(doom-themes-enable-italic t))
#+end_src
* Shortcuts
Create a custom keybinding for loading a theme with =SPC t t=:
#+begin_src emacs-lisp
(dotfiles/leader
"tt" '(counsel-load-theme t t :which-key "Theme"))
#+end_src
* Footnotes
[fn:1] https://packages.debian.org/sid/lxappearance
[fn:2] https://packages.debian.org/sid/arc-theme
[fn:3] https://github.com/hlissner/emacs-doom-themes

38
modules/trash.org

@ -1,38 +0,0 @@
#+TITLE: Trash
#+AUTHOR: Christopher James Hayward
#+EMAIL: chris@chrishayward.xyz
#+PROPERTY: header-args:emacs-lisp :tangle trash.el :comments org
#+PROPERTY: header-args :results silent :eval no-export :comments org
#+OPTIONS: num:nil toc:nil todo:nil tasks:nil tags:nil
#+OPTIONS: skip:nil author:nil email:nil creator:nil timestamp:nil
Keep the system clean of debris.
* Setup
Despite having the stateful and immutable configuration seprated, and the entire project under version control, it's still good practice to make efforts to reduce the trash created by Emacs. The package ~no-littering~ helps us achieve just that.
+ Disable ~tooltip-mode~
+ Disable ~tool-bar-mode~
+ Disable ~menu-bar-mode~
+ Disable ~scroll-bar-mode~
+ Inhibit the startup message
# + Defer ~native-comp~ compilation
+ Clear the scratch buffer instructions
+ Increase the garbage collector threshold
#+begin_src emacs-lisp
(use-package no-littering
:custom (inhibit-startup-message t)
(initial-scratch-message "")
;; (comp-deferred-compilation t)
(gc-cons-threshold most-positive-fixnum)
:config (tooltip-mode -1)
(tool-bar-mode -1)
(menu-bar-mode -1)
(scroll-bar-mode -1))
#+end_src
* Footnotes

55
modules/uml.org

@ -1,55 +0,0 @@
#+TITLE: UML
#+AUTHOR: Christopher James Hayward
#+EMAIL: chris@chrishayward.xyz
#+PROPERTY: header-args:emacs-lisp :tangle uml.el :comments org
#+PROPERTY: header-args:shell :tangle no
#+PROPERTY: header-args :results silent :eval no-export :comments org
#+OPTIONS: num:nil toc:nil todo:nil tasks:nil tags:nil
#+OPTIONS: skip:nil author:nil email:nil creator:nil timestamp:nil
Draw UML[fn:1] diagrams inside Emacs.
* Setup
Make sure all of the required components are installed on your system before loading the module.
#+begin_src shell
RUN apt install -y default-jre
#+end_src
* Config
Download and install ~PlantUML~[fn:2], a text-based markup language for creating UML[fn:1] diagrams. You can read my notes about using the software here[fn:3]. Support for Emacs is added through the ~plantuml-mode~[fn:4] package. Configure the ~babel~ language module and structure templates to write diagrams in ~org-mode~ buffers.
#+begin_src emacs-lisp
(use-package plantuml-mode
:after org
:custom (plantuml-default-exec-mode 'jar)
(plantuml-jar-path "~/.local/bin/plantuml.jar")
(org-plantuml-jar-path (expand-file-name "~/.local/bin/plantuml.jar"))
(org-startup-with-inline-images t)
:config (add-to-list 'org-src-lang-modes '("plantuml" . plantuml))
(add-to-list 'org-structure-template-alist '("pl" . "src plantuml"))
(org-babel-do-load-languages 'org-babel-load-languages '((plantuml . t))))
#+end_src
* Shortcuts
Toggle inline imagines with =SPC t i=.
#+begin_src emacs-lisp
(dotfiles/leader
"ti" '(org-toggle-inline-images :which-key "Images"))
#+end_src
* Footnotes
[fn:1] https://tutorialspoint.com/uml/uml_standard_diagrams.htm
[fn:2] https://plantuml.com
[fn:3] https://chrishayward.xyz/notes/plantuml/
[fn:4] https://github.com/skuro/plantuml-mode

43
modules/vterm.org

@ -1,43 +0,0 @@
#+TITLE: VTerm
#+AUTHOR: Christopher James Hayward
#+EMAIL: chris@chrishayward.xyz
#+PROPERTY: header-args:emacs-lisp :tangle vterm.el :comments org
#+PROPERTY: header-args :results silent :eval no-export :comments org
#+OPTIONS: num:nil toc:nil todo:nil tasks:nil tags:nil
#+OPTIONS: skip:nil author:nil email:nil creator:nil timestamp:nil
VTerm is an implementation of libvterm for Emacs.
* Setup
Install the dependencies before loading the module.
#+begin_src shell
RUN apt install -y cmake libtool libtool-bin
#+end_src
* Config
I noticed ~eshell~ wasn't enough when needing interactivity from the terminal. Going through [[https://chrishayward.xyz/notes/thinking-in-cpp/][Thinking in C++]] for one of my courses required lots of terminal interaction which ~eshell~ was unable to handle. Since ~vterm~ is based on ~libvterm~, an external C library, it's blazing fast and fully interactive. Add a few configurations:
+ Always compile the module
+ Install the required packages on *Debian/Ubuntu*
#+begin_src emacs-lisp
(use-package vterm
:commands (vterm)
:custom (vterm-always-compile-module t))
#+end_src
* Shortcuts
Open a new ~vterm~ buffer with =SPC v=:
#+begin_src emacs-lisp
(dotfiles/leader
"v" '(vterm-other-window :which-key "VTerm"))
#+end_src
* Footnotes

165
modules/x11.org

@ -1,165 +0,0 @@
#+TITLE: X11
#+AUTHOR: Christopher James Hayward
#+EMAIL: chris@chrishayward.xyz
#+PROPERTY: header-args:emacs-lisp :tangle x11.el :comments org
#+PROPERTY: header-args :results silent :eval no-export :comments org
#+OPTIONS: num:nil toc:nil todo:nil tasks:nil tags:nil
#+OPTIONS: skip:nil author:nil email:nil creator:nil timestamp:nil
X11[fn:1] is a graphical display manager.
* Setup
Install the required software on your system before loading the module. Installing X11[fn:1] without any install recommends may not include all of the packages you need on your system. Make sure you don't need any GNOME software utilities before using this example.
#+begin_src shell
RUN apt install -y xserver-xorg-core \
--no-install-recommends \
--no-install-suggests
#+end_src
** Displays
Setup ~autorandr~[fn:2] with pre-configured profiles for screen size and display output.
#+begin_src shell
RUN apt install autorandr -y
#+end_src
** Screen locking
If you want to be able to lock and unlock your screen when you're away from your machine, install ~xss-lock~[fn:3]. By default, it will show a blue screen, turning red if you input your password incorrectly, and returning to your previous screen when successful.
#+begin_src shell
RUN apt install -y xss-lock slock
#+end_src
** Desktop compositor
Download and install ~compton~[fn:4], a desktop compositor for X11[fn:1] that adds shadows, fading, translucency, and implements window frame opacity controls, inactive window transparency, and more.
#+begin_src shell
RUN apt install -y compton
#+end_src
** Desktop notifications
Make sure ~dbus~[fn:5] is installed to receive desktop notifications, it's an IPC system used by lots of utilities.
#+begin_src shell
RUN apt install -y dbus
#+end_src
* Config
:PROPERTIES:
:header-args: :tangle ../config/xinitrc :comments org
:END:
My workflow includes launching Emacs under X11[fn:1] without the use of a display manager, controlling everything within Emacs, while still providing the functionality of a desktop environment.
#+begin_src conf
compton &
xss-lock -- slock &
exec dbus-launch --exit-with-session emacs -mm --debug-init
#+end_src
** Create symbolic link
By default ~xinit~[fn:1] will read the configuration file at =$HOME/.xinitrc=. Override this location with a link to the custom configuration.
#+begin_src emacs-lisp
(dotfiles/symlink "~/.emacs.d/config/xinitrc"
"~/.xinitrc")
#+end_src
** Desktop environment
Use the ~desktop-environment~[fn:6] package to automatically bind well-known programs for controlling the volume, brightness, media playback, and many other XF86 functionality bindings.
#+begin_src emacs-lisp
(use-package desktop-environment
:after exwm
:custom (desktop-environment-brightness-small-increment "2%+")
(desktop-environment-brightness-small-decrement "2%-")
(desktop-environment-brightness-normal-decrement "5%-")
(desktop-environment-brightness-normal-decrement "5%-")
(desktop-environment-volume-small-increment "2%+")
(desktop-environment-volume-small-decrement "2%-")
(desktop-environment-volume-normal-increment "5%+")
(desktop-environment-volume-normal-decrement "5%-")
:config (desktop-environment-mode))
#+end_src
** Swapping CAPS and CTRL
:PROPERTIES:
:header-args: conf :tangle ../config/xmodmap
:END:
Use ~Xmodmap~[fn:7] to swap CapsLock and Ctrl to keep common bindings on the home row.
#+begin_src conf
clear lock
clear control
keycode 66 = Control_L
add control = Control_L
add Lock = Control_R
#+end_src
Override the configuration file.
#+begin_src emacs-lisp
(dotfiles/symlink "~/.emacs.d/config/xmodmap"
"~/.Xmodmap")
#+end_src
** Frame transparency
Emacs supports frame transparency when running under the X Window System[fn:1].
#+begin_src emacs-lisp
(defun dotfiles/toggle-transparency ()
(interactive)
(let ((alpha (frame-parameter nil 'alpha)))
(set-frame-parameter nil 'alpha
(if (eql (cond ((numberp alpha) alpha)
((numberp (cdr alpha)) (cdr alpha))
((numberp (cadr alpha)) (cadr alpha)))
100)
'(85 . 80) '(100 . 100)))))
#+end_src
Enable frame transparency by default.
#+begin_src emacs-lisp
(set-frame-parameter (selected-frame) 'alpha '(85 . 80))
(add-to-list 'default-frame-alist '(alpha . (85 . 80)))
#+end_src
* Shortcuts
Toggle frame transparency with =SPC t r=.
#+begin_src emacs-lisp
(dotfiles/leader
"tr" '(dotfiles/toggle-transparency :which-key "Transparency"))
#+end_src
* Footnotes
[fn:1] https://en.wikipedia.org/wiki/X_Window_System
[fn:2] https://github.com/phillipberndt/autorandr
[fn:3] https://man.archlinux.org/man/xss-lock.1
[fn:4] https://github.com/chjj/compton
[fn:5] https://packages.debian.org/stretch/dbus-x11
[fn:6] https://github.com/DamienCassou/desktop-environment
[fn:7] https://wiki.archlinux.org/title/Xmodmap
Loading…
Cancel
Save