I showed you my source code, pls respond
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1572 lines
47 KiB

4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
  1. #+TITLE: Dotfiles
  2. #+SUBTITLE: I showed you my source code, pls respond
  3. #+AUTHOR: Christopher James Hayward
  4. #+EMAIL: chris@chrishayward.xyz
  5. #+ROAM_KEY: https://github.com/chayward1/dotfiles/
  6. #+ATTR_ORG: :width 420px
  7. #+ATTR_HTML: :width 420px
  8. #+ATTR_LATEX: :width 420px
  9. [[./docs/images/desktop-alt.png]]
  10. Immutable GNU Emacs dotfiles. Built for Life, Liberty, and the Open Road.
  11. + 100% Literate
  12. + 100% Immutable
  13. + 100% Reproducible
  14. Heavily inspired by [[https://github.com/hlissner/doom-emacs][Doom Emacs]] and [[https://youtube.com/c/SystemCrafters][System Crafters]].
  15. * Init
  16. :PROPERTIES:
  17. :header-args: :tangle init.el
  18. :END:
  19. Although later versions of Emacs introduce =early-init.el=, it's not used in this configuration for two reasons:
  20. + It's not required due to the modularity
  21. + Maintaining support for older versions
  22. Assuming you have completed all of the following tasks prior to proceeding further:
  23. 1. Imported the =secrets=
  24. 2. Initialized the =passwords=
  25. 3. Defined the =host= file
  26. 4. Created all required symbolic links
  27. Launch emacs: ~emacs -mm --debug-init~
  28. ** Options
  29. Here's a complete list of all of the options configurable for each host, and their default values. If a host configuration does not exist, the default values will remain.
  30. Configure the system font with a single ~font-family~ and define the size, of which variations to the font size are relative to this value.
  31. #+begin_src emacs-lisp
  32. (defvar dotfiles/font
  33. "Fira Code"
  34. "Unified system font family, used on all font faces.")
  35. #+end_src
  36. #+begin_src emacs-lisp
  37. (defvar dotfiles/font-size
  38. 96
  39. "Unified font size, of which all variations are relative to.")
  40. #+end_src
  41. Used by the desktop module to find the appropriate browser.
  42. #+begin_src emacs-lisp
  43. (defvar dotfiles/browser
  44. (getenv "BROWSER")
  45. "The default browser used by the system.")
  46. #+end_src
  47. Used by the writing module to determine the system language.
  48. #+begin_src emacs-lisp
  49. (defvar dotfiles/language
  50. (getenv "LANG")
  51. "The default system language.")
  52. #+end_src
  53. All of the available modules defined in the ~dotfiles/modules-available~ constant.
  54. #+begin_src emacs-lisp
  55. (defconst dotfiles/modules-available
  56. '(core editor desktop writing projects interface)
  57. "All of the available modules for hosts to load.")
  58. #+end_src
  59. Add the modules you want to initialize to the ~dotfiles/modules~ variable.
  60. #+begin_src emacs-lisp
  61. (defvar dotfiles/modules
  62. dotfiles/modules-available
  63. "Enabled modules, modify this in your host configuration.")
  64. #+end_src
  65. Specify the emacs home, and the cache directory.
  66. #+begin_src emacs-lisp
  67. (defvar dotfiles/home
  68. user-emacs-directory
  69. "Original value of `user-emacs-directory'.")
  70. #+end_src
  71. Used to seperate the immutable configuration from the stateful package files.
  72. #+begin_src emacs-lisp
  73. (defvar dotfiles/cache
  74. (expand-file-name "~/.cache/emacs")
  75. "Where `user-emacs-directory' redirects to.")
  76. #+end_src
  77. Functionality like =completion= and =hints= delayed to avoid popups for common manuevers.
  78. #+begin_src emacs-lisp
  79. (defvar dotfiles/idle
  80. 0.0
  81. "Length of time to wait before offering completions.")
  82. #+end_src
  83. Required for the all powerful leader key.
  84. #+begin_src emacs-lisp
  85. (defvar dotfiles/leader-key
  86. "SPC"
  87. "Custom leader key for custom actions.")
  88. #+end_src
  89. The desktop module requires the global leader key set.
  90. #+begin_src emacs-lisp
  91. (defvar dotfiles/leader-key-global
  92. (concat "C-" dotfiles/leader-key)
  93. "Global leader key available everywhere.")
  94. #+end_src
  95. Define where the source repositories exist on disk, for integration with the projects module.
  96. #+begin_src emacs-lisp
  97. (defvar dotfiles/projects
  98. (expand-file-name "~/.local/source/")
  99. "Location where source code projects exist on disk.")
  100. #+end_src
  101. Where the password store exists on disk.
  102. #+begin_src emacs-lisp
  103. (defvar dotfiles/passwords
  104. (expand-file-name "~/.password-store/")
  105. "Directory containing the password store.")
  106. #+end_src
  107. ** Startup
  108. The host configuration loads (if it exist) using the systems name.
  109. #+begin_src emacs-lisp
  110. ;; Load the host configuration.
  111. (let ((host-file (concat dotfiles/home "/hosts/" system-name ".el")))
  112. (when (file-exists-p host-file)
  113. (load-file host-file)))
  114. #+end_src
  115. Load all of the enabled modules:
  116. #+begin_src emacs-lisp
  117. ;; Load the enabled modules.
  118. (dolist (m dotfiles/modules)
  119. (let ((mod-file (concat dotfiles/home "/modules/" (symbol-name m) ".el")))
  120. (when (file-exists-p mod-file)
  121. (load-file mod-file))))
  122. #+end_src
  123. * Hosts
  124. Each host system that runs Emacs has a file defined in the =hosts/= sub directory, following the pattern of ~$HOSTNAME.el~. All of the configurations definitions are in this file. Modules will read these values during initialization.
  125. ** Virtualbox
  126. :PROPERTIES:
  127. :header-args: :tangle hosts/virtualbox.el
  128. :END:
  129. The first configuration, built using the Ubuntu 20.04 LTS server edition.
  130. + Set the browser manually
  131. + Set the language to Canadian english
  132. #+begin_src emacs-lisp
  133. (setq dotfiles/browser "firefox"
  134. dotfiles/language "en_CA")
  135. #+end_src
  136. ** Acernitro
  137. :PROPERTIES:
  138. :header-args: :tangle hosts/acernitro.el
  139. :END:
  140. The first machine with real hardware to deploy this configuration to. It's an Acer Nitro AN-515 with the NVIDIA / Intel hybrid graphics card. Due to the issues I encountered with this hardware setup, I again opted to install Ubuntu 20.04, and stripped away the components I don't need.
  141. + Set the browser manually
  142. + Set the language to Canadian english
  143. + Increase font size for high DPI screen
  144. Configure the browser.
  145. #+begin_src emacs-lisp
  146. (setq dotfiles/browser "firefox"
  147. dotfiles/language "en_CA"
  148. dotfiles/font-size 132)
  149. #+end_src
  150. ** Raspberry
  151. :PROPERTIES:
  152. :header-args: :tangle hosts/raspberry.el
  153. :END:
  154. Raspberry Pi 400 personal computer, and a small fleet of Zero, Zero WH, 4, and 4Bs.
  155. + Set the browser manually
  156. + Set the language to Canadian english
  157. + Increase font size for small screens
  158. #+begin_src emacs-lisp
  159. (setq dotfiles/browser "chromium-browser"
  160. dotfiles/language "en_CA"
  161. dotfiles/font-size 132)
  162. #+end_src
  163. ** Termux
  164. :PROPERTIES:
  165. :header-args: :tangle hosts/localhost.el
  166. :END:
  167. Android devices do not use the Linux host names, so setting a custom hostname is pointless as it just changes the value of ~kernel.hostname~ and have no impact on the running system. It's recommended to leave the hostname as =localhost= in Termux. While this raises an issue with my host definition system, it's no more of an issue than the =rasberry= namespace.
  168. + Increase font size for small screen
  169. #+begin_src emacs-lisp
  170. (setq dotfiles/font-size 132)
  171. #+end_src
  172. * Modules
  173. Breaking down the project into logical units or chapters to keep the code more maintainable and organized. This is also a fundemental requirement to achieve the goal of modularity. Incorporating just the =core= module on a build server to build literate programming projects is just one example.
  174. ** Core
  175. :PROPERTIES:
  176. :header-args: :tangle modules/core.el :results silent
  177. :END:
  178. Minimal configuration to make Emacs usable for my own personal workflow. This does little in the ways of improving the visuals, only removing what's included by default and not required. Read more about my technique in my post [[file:docs/posts/immutable-emacs.org.gpg][Immutable Emacs]].
  179. *** Startup
  180. Emacs creates a lot of files relative to ~user-emacs-directory~, these files are not part of this immutable configuration and do not belong in the emacs directory. How can we solve this issue? Shortly after initialization, before most packages load, we change the value to ~dotfiles/cache~. I elaborate more on the technique in my post [[https://chrishayward.xyz/posts/immutable-emacs/][Immutable Emacs]].
  181. #+begin_src emacs-lisp
  182. (setq user-emacs-directory dotfiles/cache)
  183. #+end_src
  184. Because this project uses version-control, we can disable more unwanted features:
  185. + Lock files
  186. + Backup files
  187. #+begin_src emacs-lisp
  188. (setq create-lockfiles nil
  189. make-backup-files nil)
  190. #+end_src
  191. *** Packages
  192. Download and install packages using [[https://github.com/raxod502/straight.el][straight.el]], a functional package manager that integrates with =use-package=, giving us more control over sourcing our packages.
  193. + Use the development branch
  194. + Integrate with ~use-package~
  195. Apply the configurations prior to bootstrapping the package manager, by setting (writing) to the variables that =straight= will ultimately read from.
  196. #+begin_src emacs-lisp
  197. (setq straight-repository-branch "develop"
  198. straight-use-package-by-default t)
  199. #+end_src
  200. Bootstrap the package manager, downloading, installing, or configuring depending on the state of the configuration. All packages build from source, pinned to specific git commit hashes.
  201. #+begin_src emacs-lisp
  202. (defvar bootstrap-version)
  203. (let ((bootstrap-file
  204. (expand-file-name "straight/repos/straight.el/bootstrap.el" user-emacs-directory))
  205. (bootstrap-version 5))
  206. (unless (file-exists-p bootstrap-file)
  207. (with-current-buffer
  208. (url-retrieve-synchronously
  209. "https://raw.githubusercontent.com/raxod502/straight.el/develop/install.el"
  210. 'silent 'inhibit-cookies)
  211. (goto-char (point-max))
  212. (eval-print-last-sexp)))
  213. (load bootstrap-file nil 'nomessage))
  214. #+end_src
  215. Complete the integration with ~use-package~ by installing it with =straight=.
  216. #+begin_src emacs-lisp
  217. (straight-use-package 'use-package)
  218. #+end_src
  219. *** Cleanup
  220. Despite having our *stateful* and *immutable* configurations seperate, it's good practice to make efforts to reduce the trash created by Emacs. Install [[https://github.com/emacscollective/no-littering][no-littering]] to reduce the files created by Emacs.
  221. #+begin_src emacs-lisp
  222. (use-package no-littering)
  223. #+end_src
  224. Emacs' default user interface is *horrendous*, let's do something about that.
  225. #+begin_src emacs-lisp
  226. (setq inhibit-startup-message t
  227. initial-scratch-message "")
  228. (global-prettify-symbols-mode)
  229. (when (window-system)
  230. (tooltip-mode -1)
  231. (tool-bar-mode -1)
  232. (menu-bar-mode -1)
  233. (when (fboundp 'scroll-bar-mode)
  234. (scroll-bar-mode -1)))
  235. #+end_src
  236. Emacs has a long history of running on machines without gigabytes of available memory, let it realize its full potential! Just kidding, it just smashes *CPU0*.
  237. #+begin_src emacs-lisp
  238. (setq gc-cons-treshold most-positive-fixnum
  239. gnutls-min-prime-bits 4096)
  240. #+end_src
  241. *** Babel
  242. *Organize your plain life in plain text*
  243. [[https://orgmode.org][Org-mode]] is one of the hallmark features of Emacs, and provides the basis for my Literate Programming platform. It's essentially a markdown language with rich features for project management, scheduling, development, and writing. It's hard to convey everything within its capabilities.
  244. + [[https://orgmode.org/worg/org-contrib/babel/languages/index.html][Babel languages]]
  245. + [[https://orgmode.org/manual/Structure-Templates.html][Structure templates]]
  246. #+begin_src emacs-lisp
  247. (use-package org
  248. :hook (org-mode . (lambda ()
  249. (org-indent-mode)
  250. (visual-line-mode 1)
  251. (variable-pitch-mode 1)))
  252. :custom (org-ellipsis " ▾")
  253. (org-log-done 'time)
  254. (org-log-into-drawer t)
  255. (org-image-actual-width nil)
  256. (org-directory dotfiles/home)
  257. (org-src-preserve-indentation t)
  258. (org-todo-keywords '((sequence "TODO" "START" "WAIT" "DONE")))
  259. :config (require 'org-tempo)
  260. (add-to-list 'org-structure-template-alist '("s" . "src"))
  261. (add-to-list 'org-structure-template-alist '("q" . "quote"))
  262. (add-to-list 'org-structure-template-alist '("e" . "example"))
  263. (add-to-list 'org-structure-template-alist '("sh" . "src shell"))
  264. (add-to-list 'org-structure-template-alist '("el" . "src emacs-lisp"))
  265. (org-babel-do-load-languages 'org-babel-load-languages '((shell . t)
  266. (emacs-lisp . t))))
  267. #+end_src
  268. Build all of the =org= files within a given directory.
  269. #+begin_src emacs-lisp
  270. (defun dotfiles/tangle (dir)
  271. "Recursively tangle the Org files within a directory."
  272. (let ((org-files (directory-files-recursively dir "org")))
  273. (dolist (f org-files)
  274. (org-babel-tangle-file f))))
  275. #+end_src
  276. ** Editor
  277. :PROPERTIES:
  278. :header-args: :tangle modules/editor.el :results silent
  279. :END:
  280. This section contains configuration for improving the editor experience within Emacs.
  281. *** Keys
  282. Make the =ESC= key quit (most) prompts, instead of the default =C-g=.
  283. #+begin_src emacs-lisp
  284. (global-set-key (kbd "<escape>") 'keyboard-escape-quit)
  285. #+end_src
  286. Download [[https://github.com/justbur/emacs-which-key][which-key]], a package that displays the current incomplete keybinding input in a mini-buffer, showing available completion options.
  287. #+begin_src emacs-lisp
  288. (use-package which-key
  289. :diminish which-key-mode
  290. :custom (which-key-idle-delay dotfiles/idle)
  291. :config (which-key-mode))
  292. #+end_src
  293. Turn Emacs into Vim with [[https://evil.readthedocs.io/en/latest/index.html][evil-mode]], the extensible VI layer for Emacs.
  294. #+begin_src emacs-lisp
  295. (use-package evil
  296. :custom (evil-want-integration t) ;; Required for `evil-collection'.
  297. (evil-want-keybinding nil) ;; Same as above
  298. :config (evil-mode 1))
  299. #+end_src
  300. Unfortunately the default keybindings are *lacking*, but there is a community curated package [[https://github.com/emacs-evil/evil-collection][evil-collection]], which does a much better job implementing keybindings you would expect to find.
  301. #+begin_src emacs-lisp
  302. (use-package evil-collection
  303. :after evil
  304. :config (evil-collection-init))
  305. #+end_src
  306. Surround text with functions, quotations, and any other symbols using the [[https://github.com/emacs-evil/evil-surround][evil-surround]] package.
  307. #+begin_src emacs-lisp
  308. (use-package evil-surround
  309. :after evil
  310. :config (global-evil-surround-mode 1))
  311. #+end_src
  312. Toggle block comments using [[https://github.com/redguardtoo/evil-nerd-commenter][evil-nerd-commentor]] and =M-;=.
  313. #+begin_src emacs-lisp
  314. (use-package evil-nerd-commenter
  315. :after evil
  316. :bind ("M-;" . evilnc-comment-or-uncomment-lines))
  317. #+end_src
  318. Implement the *leader* key using [[https://github.com/noctuid/general.el][general.el]], letting us easily configure prefixed keybindings in a much cleaner manner than the default methods.
  319. #+begin_src emacs-lisp
  320. (use-package general
  321. :after evil
  322. :config
  323. (general-create-definer dotfiles/leader
  324. :states '(normal motion)
  325. :keymaps 'override
  326. :prefix dotfiles/leader-key
  327. :global-prefix dotfiles/leader-key-global))
  328. #+end_src
  329. Use [[https://github.com/abo-abo/hydra][hydra]] for transient keybindings sharing a common prefix.
  330. #+begin_src emacs-lisp
  331. (use-package hydra
  332. :defer t)
  333. #+end_src
  334. *** Help
  335. Use the built-in ~describe-*~ functionality of Emacs to quickly access documentation for packages, variables, and functions. Run helper functions with =SPC h=.
  336. + Packages =p=
  337. + Variables =v=
  338. + Functions =f=
  339. #+begin_src emacs-lisp
  340. (dotfiles/leader
  341. "h" '(:ignore t :which-key "Help")
  342. "hp" '(describe-package :which-key "Package")
  343. "hv" '(describe-variable :which-key "Variable")
  344. "hf" '(describe-function :which-key "Function"))
  345. #+end_src
  346. *** Files
  347. For file navigation I use =dired=, included with Emacs by default. Dired feels more modern with prioritized icon fonts using [[https://github.com/domtronn/all-the-icons.el][all-the-icons]]. This makes navigation and visually parsing directories much faster, given that file types are quickly identified by their corresponding icons.
  348. #+begin_src emacs-lisp
  349. (use-package all-the-icons)
  350. #+end_src
  351. Integration with =dired= comes from the [[https://github.com/jtbm37/all-the-icons-dired][all-the-icons-dired]] package.
  352. #+begin_src emacs-lisp
  353. (use-package all-the-icons-dired
  354. :hook (dired-mode . all-the-icons-dired-mode))
  355. #+end_src
  356. When opening =dired=, I don't want to have to press =RET= twice to navigate to the current directory. Avoid this with ~dired-jump~, included in the =dired-x= package shipped with =dired= and Emacs.
  357. #+begin_src emacs-lisp
  358. (require 'dired-x)
  359. #+end_src
  360. By default =dired= will create a new buffer everytime you press =RET= over a directory. This leads to unwanted =dired= buffers needing closure. Avoid this behaviour with [[https://github.com/crocket/dired-single][dired-single]], reusing the same dired buffer.
  361. + Move up a directory with =h=
  362. + Open a single buffer with =l=
  363. #+begin_src emacs-lisp
  364. (use-package dired-single
  365. :config (evil-collection-define-key 'normal 'dired-mode-map
  366. "h" 'dired-single-up-directory
  367. "l" 'dired-single-buffer))
  368. #+end_src
  369. Open a dired buffer with =SPC d=.
  370. #+begin_src emacs-lisp
  371. (dotfiles/leader
  372. "d" '(dired-jump :which-key "Dired"))
  373. #+end_src
  374. *** Shell
  375. While not a traditional terminal emulator, =eshell= provides me with all of the functionality I expect and require from one. Some users may be wanting more, I would recommend they look into =vterm= included in the destkop module. Configure the infamous lambda prompt using [[https://github.com/zwild/eshell-prompt-extras][eshell-prompt-extras]] package.
  376. #+begin_src emacs-lisp
  377. (use-package eshell-prompt-extras
  378. :custom (eshell-highlight-prompt nil)
  379. (eshell-prompt-function 'epe-theme-lambda))
  380. #+end_src
  381. Open an =eshell= buffer with =SPC e=.
  382. #+begin_src emacs-lisp
  383. (dotfiles/leader
  384. "e" '(eshell :which-key "Shell"))
  385. #+end_src
  386. *** Source
  387. #+ATTR_ORG: :width 420px
  388. #+ATTR_HTML: :width 420px
  389. #+ATTR_LATEX: :width 420px
  390. [[./docs/images/2021-02-13-example-magit.gif]]
  391. Another hallmark feature is [[https://github.com/magit/magit][Magit]], a complete git porcelain within Emacs.
  392. #+begin_src emacs-lisp
  393. (use-package magit
  394. :commands magit-status
  395. :custom (magit-display-buffer-function
  396. #'magit-display-buffer-same-window-except-diff-v1))
  397. #+end_src
  398. Work directly with github issues / pull requests using [[https://github.com/magit/forge][Forge]].
  399. + Requires a valid ~$GITHUB_TOKEN~
  400. #+begin_src emacs-lisp
  401. (use-package forge
  402. :after magit)
  403. #+end_src
  404. Open the *status* page for the current repository with =SPC g=.
  405. #+begin_src emacs-lisp
  406. (dotfiles/leader
  407. "g" '(magit-status :which-key "Magit"))
  408. #+end_src
  409. *** Windows
  410. Window management with =SPC w=.
  411. + Swap with =w=
  412. + Close with =c=
  413. + Motions with =h,j,k,l=
  414. + Split with =s + <MOTION>=
  415. #+begin_src emacs-lisp
  416. (dotfiles/leader
  417. "w" '(:ignore t :which-key "Window")
  418. "ww" '(window-swap-states :which-key "Swap")
  419. "wc" '(delete-window :which-key "Close")
  420. "wh" '(windmove-left :which-key "Left")
  421. "wj" '(windmove-down :which-key "Down")
  422. "wk" '(windmove-up :which-key "Up")
  423. "wl" '(windmove-right :which-key "Right")
  424. "ws" '(:ignore t :which-key "Split")
  425. "wsj" '(split-window-below :which-key "Down")
  426. "wsl" '(split-window-right :which-key "Right"))
  427. #+end_src
  428. *** Shortcuts
  429. Implement shortcut bindings, cherry picked from Doom emacs.
  430. + Close buffers with =SPC c=
  431. + Find files with =SPC . (period)=
  432. #+begin_src emacs-lisp
  433. (dotfiles/leader
  434. "." '(find-file :which-key "Files")
  435. "c" '(kill-buffer-and-window :which-key "Close"))
  436. #+end_src
  437. Quit emacs with =SPC q=.
  438. + Saving =q=
  439. + Without =w=
  440. + Frame (daemon) =f=
  441. #+begin_src emacs-lisp
  442. (dotfiles/leader
  443. "q" '(:ignore t :which-key "Quit")
  444. "qq" '(save-buffers-kill-emacs :which-key "Save")
  445. "qw" '(kill-emacs :which-key "Now")
  446. "qf" '(delete-frame :which-key "Frame"))
  447. #+end_src
  448. Place runtime tweaks behind =SPC t=.
  449. #+begin_src emacs-lisp
  450. (dotfiles/leader
  451. "t" '(:ignore t :which-key "Tweaks"))
  452. #+end_src
  453. ** Desktop
  454. :PROPERTIES:
  455. :header-args: :tangle modules/desktop.el :results silent
  456. :END:
  457. I use Emacs as a Desktop Environment with the [[https://github.com/ch11ng/exwm][exwm]] package. It allows Emacs to function as a complete tiling window manager for =X11=. My workflow includes launching the window manager with =xinitrc=, without the use of a display manager, controlling *everything* within Emacs.
  458. #+begin_src conf :tangle config/xinitrc
  459. exec dbus-launch --exit-with-session emacs -mm --debug-init
  460. #+end_src
  461. *** Email
  462. #+ATTR_ORG: :width 420px
  463. #+ATTR_HTML: :width 420px
  464. #+ATTR_LATEX: :width 420px
  465. [[./docs/images/2021-02-13-example-mu4e.gif]]
  466. Plain text email delivered via mu, mu4e and mbsync. I run my own email server, so your configuration may differ from mine. This is the ~mbsyncrc~ file I use to synchronize my local mail with my server.
  467. #+begin_src conf :tangle config/mbsyncrc
  468. IMAPStore xyz-remote
  469. Host mail.chrishayward.xyz
  470. User chris@chrishayward.xyz
  471. PassCmd "pass chrishayward.xyz/chris"
  472. SSLType IMAPS
  473. MaildirStore xyz-local
  474. Path ~/.cache/mail/
  475. Inbox ~/.cache/mail/inbox
  476. SubFolders Verbatim
  477. Channel xyz
  478. Master :xyz-remote:
  479. Slave :xyz-local:
  480. Patterns * !Archives
  481. Create Both
  482. Expunge Both
  483. SyncState *
  484. #+end_src
  485. 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.
  486. #+begin_src shell :tangle no
  487. mbsync -a
  488. mu index --maildir="~/.cache/mail"
  489. #+end_src
  490. Once the mail's synchronized, and has indexed with =mu=, it's time to install the required packages for Emacs.
  491. + Update every 5 minutes
  492. + Scale text for all devices
  493. + Sign outbound mail with GPG key
  494. + Configure mail account(s)
  495. #+begin_src emacs-lisp
  496. (use-package mu4e
  497. :load-path "/usr/share/emacs/site-lisp/mu4e"
  498. :custom (mu4e-maildir "~/.cache/mail")
  499. (mu4e-update-interval (* 5 60))
  500. (mu4e-get-mail-command "mbsync -a")
  501. (mu4e-compose-format-flowed t)
  502. (mu4e-change-filenames-when-moving t)
  503. (message-send-mail-function 'smtpmail-send-it)
  504. (mml-secure-openpgp-signers '("37AB1CB72B741E478CA026D43025DCBD46F81C0F"))
  505. (mu4e-compose-signature (concat "Chris Hayward\n"
  506. "https://chrishayward.xyz\n"))
  507. :config
  508. (add-hook 'message-send-hook 'mml-secure-message-sign-pgpmime)
  509. (setq mu4e-contexts
  510. (list
  511. ;; Main
  512. ;; chris@chrishayward.xyz
  513. (make-mu4e-context
  514. :name "Main"
  515. :match-func
  516. (lambda (msg)
  517. (when msg
  518. (string-prefix-p "/Main" (mu4e-message-field msg :maildir))))
  519. :vars
  520. '((user-full-name . "Christopher James Hayward")
  521. (user-mail-address . "chris@chrishayward.xyz")
  522. (smtpmail-smtp-server . "mail.chrishayward.xyz")
  523. (smtpmail-smtp-service . 587)
  524. (smtpmail-stream-type . starttls))))))
  525. #+end_src
  526. Use [[https://github.com/iqbalansari/mu4e-alert][mu4e-alert]] to give us desktop notifications about incoming mail.
  527. #+begin_src emacs-lisp
  528. (use-package mu4e-alert
  529. :after mu4e
  530. :custom (mu4e-alert-set-default-style 'libnotify)
  531. :config (mu4e-alert-enable-notifications)
  532. (mu4e-alert-enable-mode-line-display))
  533. #+end_src
  534. Create a keybinding to open the mail dashboard with =SPC m=.
  535. #+begin_src emacs-lisp
  536. (dotfiles/leader
  537. "m" '(mu4e :which-key "Mail"))
  538. #+end_src
  539. *** Browser
  540. Write out the ~$BROWSER~ environment variable.
  541. #+begin_src emacs-lisp
  542. (setenv "BROWSER" dotfiles/browser)
  543. #+end_src
  544. *** Startup
  545. :PROPERTIES:
  546. :header-args: :tangle config/profile
  547. :END:
  548. Ensure that ~/.local/bin~ is added to the path.
  549. #+begin_src sh
  550. PATH=$PATH:~/.local/bin
  551. export PATH
  552. #+end_src
  553. When launching into a session, if the display server is not running then =startx= executes to run the window manager.
  554. #+begin_src sh
  555. if [ -z "${DISPLAY}" ] && [ "${XDG_VTNR}" -eq 1 ]; then
  556. exec startx
  557. fi
  558. #+end_src
  559. *** Methods
  560. Define a method to run an external process, allowing us to launch any application on a new process without interferring with Emacs.
  561. #+begin_src emacs-lisp
  562. (defun dotfiles/run (command)
  563. "Run an external process."
  564. (interactive (list (read-shell-command "λ ")))
  565. (start-process-shell-command command nil command))
  566. #+end_src
  567. Apply methods to the current call process to avoid issues with hooks.
  568. #+begin_src emacs-lisp
  569. (defun dotfiles/run-in-background (command)
  570. (let ((command-parts (split-string command "[ ]+")))
  571. (apply #'call-process `(,(car command-parts) nil 0 nil ,@(cdr command-parts)))))
  572. #+end_src
  573. Place keybindings for executing shell commands behind =SPC x=.
  574. + Run shell commands with =x=
  575. + Run async shell commands with =z=
  576. #+begin_src emacs-lisp
  577. (dotfiles/leader
  578. "x" '(:ignore t :which-key "Run")
  579. "xx" '(dotfiles/run :which-key "Run")
  580. "xz" '(async-shell-command :which-key "Async"))
  581. #+end_src
  582. *** Displays
  583. When the window manager first launches the ~init-hook~ executes, allowing us to define some custom logic.
  584. + Display time and date
  585. + Display battery info (if available)
  586. In my personal configuration, I do not want the battery or time displayed within Emacs when it's not running as desktop environment because that information is typically already available.
  587. #+begin_src emacs-lisp
  588. (defun dotfiles/init-hook ()
  589. (exwm-workspace-switch-create 1)
  590. (setq display-time-and-date t)
  591. (display-battery-mode 1)
  592. (display-time-mode 1))
  593. #+end_src
  594. Using =autorandr= with pre configured profiles, switching screens (AKA hot plugging) is also handled through a hook.
  595. #+begin_src emacs-lisp
  596. (defun dotfiles/update-display ()
  597. "Update the displays by forcing a change through autorandr."
  598. (dotfiles/run-in-background "autorandr --change --force"))
  599. #+end_src
  600. *** Configuration
  601. Connect our custom hooks and configure the input keys, a custom layer for key capture layers.
  602. + Enable =randr= support
  603. + Pass through to Emacs
  604. + =M-x= to Emacs
  605. + =C-g= to Emacs
  606. + =C-SPC= to Emacs
  607. + Bindings with =S= (Super / Win)
  608. + Reset =S-r=
  609. + Launch =S-&=
  610. + Workspace =S-[1..9]=
  611. #+begin_src emacs-lisp
  612. (use-package exwm
  613. :custom (exwm-workspace-show-all-buffers t)
  614. (exwm-input-prefix-keys
  615. '(?\M-x
  616. ?\C-c
  617. ?\C-g
  618. ?\C-\ ))
  619. (exwm-input-global-keys
  620. `(([?\s-r] . exwm-reset)
  621. ,@(mapcar (lambda (i)
  622. `(,(kbd (format "s-%d" i)) .
  623. (lambda ()
  624. (interactive)
  625. (exwm-workspace-switch-create ,i))))
  626. (number-sequence 1 9))))
  627. :config (require 'exwm-randr)
  628. (exwm-randr-enable)
  629. (add-hook 'exwm-init-hook #'dotfiles/init-hook)
  630. (add-hook 'exwm-randr-screen-change-hook #'dotfiles/update-display)
  631. (dotfiles/update-display)
  632. (exwm-enable))
  633. #+end_src
  634. ** Writing
  635. :PROPERTIES:
  636. :header-args: :tangle modules/writing.el :results silent
  637. :END:
  638. I am using [[https://orgmode.org][org-mode]] extensively for writing projects for different purposes. Most of the improvements are done in the *Core* module for the Literate programming configuration. [[https://github.com/integral-dw/org-superstar-mode][org-superstar-mode]] for making headline stars more *super*.
  639. #+begin_src emacs-lisp
  640. (use-package org-superstar
  641. :after org
  642. :hook (org-mode . org-superstar-mode))
  643. #+end_src
  644. Encrypt files using symmetric key encryption via PGP. This enables my workflow of storing my personal notes anywhere. Emacs can cache the gpg password if you trust your session.
  645. #+begin_src emacs-lisp
  646. (setq epa-file-select-keys 2
  647. epa-file-cache-passphrase-for-symmetric-encryption t
  648. epa-file-encrypt-to "37AB1CB72B741E478CA026D43025DCBD46F81C0F")
  649. #+end_src
  650. *** Roam
  651. #+ATTR_ORG: :width 420px
  652. #+ATTR_HTML: :width 420px
  653. #+ATTR_LATEX: :width 420px
  654. [[./docs/images/2021-02-13-example-roam.png]]
  655. Download and install [[https://orgroam.com][org-roam]], a plain text knowledge management system for Emacs.
  656. #+begin_src emacs-lisp
  657. (use-package org-roam
  658. :hook (after-init . org-roam-mode)
  659. :custom (org-roam-directory org-directory)
  660. (org-roam-encrypt-files t)
  661. (org-roam-capture-templates '())
  662. (org-roam-dailies-capture-templates
  663. '(("d" "Default" entry (function org-roam-capture--get-point)
  664. "* %?"
  665. :file-name "docs/daily/%<%Y-%m-%d>"
  666. :head
  667. "
  668. ,#+TITLE: %<%Y-%m-%d>
  669. ,#+AUTHOR: Christopher James Hayward
  670. "))))
  671. #+end_src
  672. Place keybindings behind =SPC r=.
  673. + Find with =f=
  674. + Toggle buffer with =b=
  675. + Dailies with =d=
  676. + Arbitrary date with =d=
  677. + Today with =t=
  678. + Tomorrow with =m=
  679. + Yesterday with =y=
  680. #+begin_src emacs-lisp
  681. (dotfiles/leader
  682. "r" '(:ignore t :which-key "Roam")
  683. "rf" '(org-roam-find-file :which-key "Find")
  684. "rb" '(org-roam-buffer-toggle-display :which-key "Buffer")
  685. "rd" '(:ignore t :which-key "Dailies")
  686. "rdd" '(org-roam-dailies-find-date :which-key "Date")
  687. "rdt" '(org-roam-dailies-find-today :which-key "Today")
  688. "rdm" '(org-roam-dailies-find-tomorrow :which-key "Tomorrow")
  689. "rdy" '(org-roam-dailies-find-yesterday :which-key "Yesterday"))
  690. #+end_src
  691. Visualize the org-roam database with the server, available when the editor is running at http://localhost:8080
  692. #+begin_src emacs-lisp
  693. (use-package org-roam-server
  694. :hook (org-roam-mode . org-roam-server-mode))
  695. #+end_src
  696. *** Hugo
  697. I use [[https://gohugo.io][Hugo]] for my personal [[https://chrishayward.xyz][website]], which I write in =org-mode= before compiling to =hugo-markdown=. [[https://github.com/kaushalmodi/ox-hugo][ox-hugo]], configured for =one-post-per-file= is my technique for managing my content.
  698. #+begin_src emacs-lisp
  699. (use-package ox-hugo
  700. :after ox)
  701. #+end_src
  702. *** Posts
  703. Add a capture template for creatinhg new blog posts.
  704. #+begin_src emacs-lisp
  705. (with-eval-after-load 'org-roam
  706. (add-to-list 'org-roam-capture-templates
  707. '("p" "Post" plain (function org-roam-capture--get-point)
  708. "%?"
  709. :file-name "docs/posts/${slug}"
  710. :unnarrowed t
  711. :head
  712. "
  713. ,#+TITLE: ${title}
  714. ,#+AUTHOR: Christopher James Hayward
  715. ,#+DATE: %<%Y-%m-%d>
  716. ,#+EXPORT_FILE_NAME: ${slug}
  717. ,#+ROAM_KEY: https://chrishayward.xyz/posts/${slug}/
  718. ,#+HUGO_BASE_DIR: ../
  719. ,#+HUGO_AUTO_SET_LASTMOD: t
  720. ,#+HUGO_SECTION: posts
  721. ,#+HUGO_DRAFT: true
  722. ")))
  723. #+end_src
  724. *** Notes
  725. Add a capture template for creating blog posts and notes on other peoples content / published works.
  726. #+begin_src emacs-lisp
  727. (with-eval-after-load 'org-roam
  728. (add-to-list 'org-roam-capture-templates
  729. '("n" "Notes" plain (function org-roam-capture--get-point)
  730. "%?"
  731. :file-name "docs/notes/${slug}"
  732. :unnarrowed t
  733. :head
  734. "
  735. ,#+TITLE: ${title}
  736. ,#+AUTHOR: Christopher James Hayward
  737. ,#+EXPORT_FILE_NAME: ${slug}
  738. ,#+ROAM_KEY: https://chrishayward.xyz/notes/${slug}/
  739. ,#+HUGO_BASE_DIR: ../
  740. ,#+HUGO_AUTO_SET_LASTMOD: t
  741. ,#+HUGO_SECTION: notes
  742. ,#+HUGO_DRAFT: true
  743. ")))
  744. #+end_src
  745. *** Slides
  746. Produce high quality presentations that work anywhere with =HTML/JS= and the [[https://revealjs.com][reveal.js]] package. [[https://github.com/hexmode/ox-reveal][ox-reveal]], configured to use a =cdn= allows us to produce ones that are not dependent on a local version of =reveal.js=.
  747. #+begin_src emacs-lisp
  748. (use-package ox-reveal
  749. :after ox
  750. :custom (org-reveal-root "https://cdn.jsdelivr.net/npm/reveal.js"))
  751. #+end_src
  752. Create a capture template for creating slides quickly, with our desired configuration.
  753. #+begin_src emacs-lisp
  754. (with-eval-after-load 'org-roam
  755. (add-to-list 'org-roam-capture-templates
  756. '("s" "Slides" plain (function org-roam-capture--get-point)
  757. "%?"
  758. :file-name "docs/slides/${slug}"
  759. :unnarrowed t
  760. :head
  761. "
  762. ,#+TITLE: ${title}
  763. ,#+AUTHOR: Christopher James Hayward
  764. ,#+EXPORT_FILE_NAME: ${slug}
  765. ,#+OPTIONS: toc:nil num:nil reveal_title_slide:nil
  766. ,#+REVEAL_ROOT: https://cdn.jsdelivr.net/npm/reveal.js
  767. ,#+REVEAL_THEME: serif
  768. ")))
  769. #+end_src
  770. *** Agenda
  771. #+ATTR_ORG: :width 420px
  772. #+ATTR_HTML: :width 420px
  773. #+ATTR_LATEX: :width 420px
  774. [[./docs/images/2021-02-13-example-agenda.gif]]
  775. Override ~org-agenda-file-regexp~ to include =.org.gpg= files.
  776. #+begin_src emacs-lisp
  777. (unless (string-match-p "\\.gpg" org-agenda-file-regexp)
  778. (setq org-agenda-file-regexp
  779. (replace-regexp-in-string "\\\\\\.org" "\\\\.org\\\\(\\\\.gpg\\\\)?"
  780. org-agenda-file-regexp)))
  781. #+end_src
  782. Create a capture template for courses.
  783. #+begin_src emacs-lisp
  784. (with-eval-after-load 'org-roam
  785. (add-to-list 'org-roam-capture-templates
  786. '("c" "Course" plain (function org-roam-capture--get-point)
  787. "%?"
  788. :file-name "docs/courses/${slug}"
  789. :unnarrowed t
  790. :head
  791. "
  792. ,#+TITLE: ${title}
  793. ,#+SUBTITLE:
  794. ,#+AUTHOR: Christopher James Hayward
  795. ")))
  796. #+end_src
  797. Configure agenda sources.
  798. #+begin_src emacs-lisp
  799. (setq org-agenda-files '("~/.emacs.d/docs/"
  800. "~/.emacs.d/docs/courses/"
  801. "~/.emacs.d/docs/daily/"))
  802. #+end_src
  803. Open an agenda buffer with =SPC a=.
  804. #+begin_src emacs-lisp
  805. (dotfiles/leader
  806. "a" '(org-agenda :which-key "Agenda"))
  807. #+end_src
  808. *** Images
  809. Capture screenshots with [[https://github.com/tecosaur/screenshot][screenshot.el]].
  810. #+begin_src emacs-lisp
  811. (use-package screenshot
  812. :commands (screenshot))
  813. #+end_src
  814. Create screencasts with =one-frame-per-action= GIF recording via [[https://github.com/takaxp/emacs-gif-screencast][emacs-gif-screencast]].
  815. + Pause / Resume
  816. + High Quality
  817. + Optimized
  818. It requires the installation of ~scrot~, ~gifsicle~, and ~convert~ from the =ImageMagick= library.
  819. #+begin_src emacs-lisp
  820. (use-package gif-screencast
  821. :commands (gif-screencast-start-or-stop gif-screencast-toggle-pause)
  822. :custom (gif-screencast-output-directory (concat dotfiles/home "docs/images/")))
  823. #+end_src
  824. Place keybindings behind =SPC s=.
  825. + Screenshot with =s=
  826. + Screencast with =c=
  827. #+begin_src emacs-lisp
  828. (dotfiles/leader
  829. "s" '(:ignore t :which-key "Screen")
  830. "ss" '(screenshot :which-key "Screenshot")
  831. "sc" '(gif-screencast-start-or-stop :which-key "Screencast"))
  832. #+end_src
  833. *** Grammar
  834. I use [[https://github.com/bnbeckwith/writegood-mode][writegood-mode]] to find common writing problems such as cliches and poor wording. Grammarly for the peons!
  835. #+begin_src emacs-lisp
  836. (use-package writegood-mode
  837. :after org
  838. :config (writegood-mode))
  839. #+end_src
  840. Toggle ~writegood~ mode with =SPC t w=.
  841. #+begin_src emacs-lisp
  842. (dotfiles/leader
  843. "tw" '(writegood-mode :which-key "Grammar"))
  844. #+end_src
  845. *** Spelling
  846. Use the built in =ispell= package to add spell checking features to buffers.
  847. #+begin_src emacs-lisp
  848. (use-package ispell
  849. :after org
  850. :custom (ispell-dictionary dotfiles/lang))
  851. #+end_src
  852. ** Projects
  853. :PROPERTIES:
  854. :header-args: :tangle modules/projects.el :results silent
  855. :END:
  856. An IDE like experience (or better) can be achieved in Emacs using two *Microsoft* open source initiatives.
  857. + [[https://microsoft.github.io/language-server-protocol/][Language Server Protocol]]
  858. + [[https://microsoft.github.io/debug-adapter-protocol/][Debug Adapter Protocol]]
  859. Add support for language servers with [[https://emacs-lsp.github.io/lsp-mode/][lsp-mode]].
  860. #+begin_src emacs-lisp
  861. (use-package lsp-mode
  862. :commands (lsp lsp-deferred)
  863. :custom (lsp-idle-delay (* 5 dotfiles/idle)))
  864. #+end_src
  865. [[https://emacs-lsp.github.io/lsp-ui/][lsp-ui]] provides UI improvements for =lsp-mode=.
  866. #+begin_src emacs-lisp
  867. (use-package lsp-ui
  868. :after lsp
  869. :custom (lsp-ui-doc-position 'at-point)
  870. (lsp-ui-doc-delay 0.500))
  871. #+end_src
  872. [[https://emacs-lsp.github.io/dap-mode/][Dap-mode]] adds support for the debug adapter protocol to Emacs.
  873. #+begin_src emacs-lisp
  874. (use-package dap-mode
  875. :commands (dap-debug))
  876. #+end_src
  877. *** Containers
  878. Use ~docker~ for running containers. Download and install https://github.com/Silex/docker.el, allowing us to manage containers within Emacs.
  879. #+begin_src emacs-lisp
  880. (use-package docker
  881. :commands (docker))
  882. #+end_src
  883. Open the management screen with =SPC k=.
  884. #+begin_src emacs-lisp
  885. (dotfiles/leader
  886. "k" '(docker :which-key "Docker"))
  887. #+end_src
  888. *** Management
  889. Configure [[https://projectile.mx][projectile]], a project interaction library for Emacs. It provides a nice set of features for operating on a project level without introducing external dependencies.
  890. #+begin_src emacs-lisp
  891. (use-package projectile
  892. :custom (projectile-project-search-path '("~/.local/source"))
  893. :config (projectile-mode))
  894. #+end_src
  895. *** Completion
  896. Text completion framework via =company= aka *Complete Anything*.
  897. http://company-mode.github.io/
  898. + Integrate with =lsp-mode=
  899. #+begin_src emacs-lisp
  900. (use-package company
  901. :after lsp)
  902. (use-package company-lsp
  903. :after (lsp company)
  904. :custom (company-backend 'company-lsp))
  905. #+end_src
  906. *** Passwords
  907. Pass makes managing passwords extremely easy, encrypring them in a file structure and providing easy commands for generating, modify, and copying passwords. =password-store.el= provides a wrapper for the functionality within Emacs.
  908. #+begin_src emacs-lisp
  909. (use-package password-store
  910. :custom (password-store-dir dotfiles/passwords))
  911. #+end_src
  912. Configure keybindings behind =SPC p=.
  913. + Copy with =p=
  914. + Rename with =r=
  915. + Generate with =g=
  916. #+begin_src emacs-lisp
  917. (dotfiles/leader
  918. "p" '(:ignore t :which-key "Passwords")
  919. "pp" '(password-store-copy :which-key "Copy")
  920. "pr" '(password-store-rename :which-key "Rename")
  921. "pg" '(password-store-generate :which-key "Generate"))
  922. #+end_src
  923. *** Languages
  924. Support for individual languages are implemented here.
  925. **** Go
  926. Install the =gopls= language server.
  927. #+begin_src sh :tangle no
  928. GO111MODULE=on go get golang.org/x/tools/gopls@latest
  929. #+end_src
  930. Set the ~GOPATH~ environment variable prior to loading, this allows us to change the default value of ~$HOME/go~ to ~$HOME/.go~.
  931. #+begin_src emacs-lisp
  932. (setenv "GOPATH" (concat (getenv "HOME") "/.go/"))
  933. #+end_src
  934. Additionally, include the =bin= subdirectory of the ~$GOPATH~ in the ~$PATH~ variable, adding compiled golang programs.
  935. #+begin_src emacs-lisp
  936. (setenv "PATH" (concat (getenv "GOPATH") "bin:" (getenv "PATH")))
  937. #+end_src
  938. Finally we can include the =go-mode= package, integrating it with =lsp=.
  939. #+begin_src emacs-lisp
  940. (use-package go-mode
  941. :hook (go-mode . lsp)
  942. :custom (lsp-go-gopls-server-path "~/.go/bin/gopls"))
  943. #+end_src
  944. Apply some custom behaviour before saving:
  945. + Format buffer
  946. + Organize imports
  947. #+begin_src emacs-lisp
  948. (defun dotfiles/go-hook ()
  949. (add-hook 'before-save-hook #'lsp-format-buffer t t)
  950. (add-hook 'before-save-hook #'lsp-organize-imports t t))
  951. #+end_src
  952. #+begin_src emacs-lisp
  953. (add-hook 'go-mode-hook #'dotfiles/go-hook)
  954. #+end_src
  955. Add a golang source code block structure template with ~<go~:
  956. #+begin_src emacs-lisp
  957. (add-to-list 'org-structure-template-alist '("go" . "src go"))
  958. #+end_src
  959. **** HTTP
  960. Instead of the popular =restclient= package, I use [[https://github.com/zweifisch/ob-http][ob-http]] as a lightweight alternative.
  961. #+begin_src emacs-lisp
  962. (use-package ob-http
  963. :after org
  964. :config (org-babel-do-load-languages
  965. 'org-babel-load-languages
  966. '((http . t))))
  967. #+end_src
  968. **** C/C++
  969. #+ATTR_ORG: :width 420px
  970. #+ATTR_HTML: :width 420px
  971. #+ATTR_LATEX: :width 420px
  972. [[./docs/images/2021-02-13-example-ccls.gif]]
  973. Add support for C/C++ languages.
  974. + Configure the [[https://github.com/MaskRay/ccls][ccls]] language server
  975. + Load babel language modules for C/C++
  976. + Create a new structure templates for C/C++
  977. - ~<cc~ for C
  978. - ~<cpp~ for C++
  979. #+begin_src emacs-lisp
  980. (use-package ccls
  981. :hook ((c-mode c++-mode objc-mode cuda-mode) .
  982. (lambda ()
  983. (require 'ccls)
  984. (lsp-deferred)))
  985. :config (add-to-list 'org-structure-template-alist '("cc" . "src C"))
  986. (add-to-list 'org-structure-template-alist '("cpp" . "src C++"))
  987. (org-babel-do-load-languages 'org-babel-load-languages '((C . t))))
  988. #+end_src
  989. **** Python
  990. Install the =pyls= language server.
  991. #+begin_src shell :tangle no
  992. pip3 install --user "python-language-server[all]"
  993. #+end_src
  994. [[https://www.emacswiki.org/emacs/PythonProgrammingInEmacs][Python-mode]] is an Emacs built in mode.
  995. + Load the babel language module for Python
  996. + Add a python source code block structure template with ~<py~
  997. #+begin_src emacs-lisp
  998. (use-package python-mode
  999. :hook (python-mode . lsp-deferred)
  1000. :config (require 'dap-python)
  1001. (add-to-list 'org-src-lang-modes '("python" . python))
  1002. (add-to-list 'org-structure-template-alist '("py" . "src python"))
  1003. (org-babel-do-load-languages 'org-babel-load-languages '((python . t)))
  1004. :custom (python-shell-interpreter "python3") ;; Required if "python" is not python 3.
  1005. (dap-python-executable "python3") ;; Same as above.
  1006. (dap-python-debugger 'debugpy))
  1007. #+end_src
  1008. **** PlantUML
  1009. Download and install [[https://plantuml.com][PlantUML]], a text-based markup language for creating UML diagrams.
  1010. + Load the babel language module for PlantUML
  1011. + Create a structure template with ~<pl~
  1012. #+begin_src emacs-lisp
  1013. (use-package plantuml-mode
  1014. :after org
  1015. :custom (plantuml-default-exec-mode 'jar)
  1016. (plantuml-jar-path "~/.local/bin/plantuml.jar")
  1017. (org-plantuml-jar-path (expand-file-name "~/.local/bin/plantuml.jar"))
  1018. (org-startup-with-inline-images t)
  1019. :config (add-to-list 'org-src-lang-modes '("plantuml" . plantuml))
  1020. (add-to-list 'org-structure-template-alist '("pl" . "src plantuml"))
  1021. (org-babel-do-load-languages 'org-babel-load-languages '((plantuml . t))))
  1022. #+end_src
  1023. Toggle inline images with =SPC t i=.
  1024. #+begin_src emacs-lisp
  1025. (dotfiles/leader
  1026. "ti" '(org-toggle-inline-images :which-key "Images"))
  1027. #+end_src
  1028. ** Interface
  1029. :PROPERTIES:
  1030. :header-args: :tangle modules/interface.el :results silent
  1031. :END:
  1032. #+ATTR_ORG: :width 420px
  1033. #+ATTR_HTML: :width 420px
  1034. #+ATTR_LATEX: :width 420px
  1035. [[./docs/images/what-is-emacs-teaser.png]]
  1036. *Bring Emacs out of the eighties*
  1037. *** Ivy
  1038. Download and configure [[https://oremacs.com/swiper/][ivy]], a powerful selection menu for Emacs.
  1039. #+begin_src emacs-lisp
  1040. (use-package ivy
  1041. :diminish
  1042. :config (ivy-mode 1))
  1043. #+end_src
  1044. Counsel is a customized set of commands to replace built in completion buffers.
  1045. #+begin_src emacs-lisp
  1046. (use-package counsel
  1047. :after ivy
  1048. :custom (counsel-linux-app-format-function #'counsel-linux-app-format-function-name-only)
  1049. :config (counsel-mode 1))
  1050. #+end_src
  1051. Switch buffers with =SPC , (comma)=.
  1052. #+begin_src emacs-lisp
  1053. (dotfiles/leader
  1054. "," '(counsel-switch-buffer :which-key "Buffers"))
  1055. #+end_src
  1056. Provide more information about each item with [[https://github.com/Yevgnen/ivy-rich][ivy-rich]].
  1057. #+begin_src emacs-lisp
  1058. (use-package ivy-rich
  1059. :after counsel
  1060. :init (ivy-rich-mode 1))
  1061. #+end_src
  1062. *** Fonts
  1063. Write out to all *3* of Emacs' default font faces.
  1064. #+begin_src emacs-lisp
  1065. (set-face-attribute 'default nil :font dotfiles/font :height dotfiles/font-size)
  1066. (set-face-attribute 'fixed-pitch nil :font dotfiles/font :height dotfiles/font-size)
  1067. (set-face-attribute 'variable-pitch nil :font dotfiles/font :height dotfiles/font-size)
  1068. #+end_src
  1069. Define a transient keybinding for scaling the text.
  1070. #+begin_src emacs-lisp
  1071. (defhydra hydra-text-scale (:timeout 4)
  1072. "Scale"
  1073. ("j" text-scale-increase "Increase")
  1074. ("k" text-scale-decrease "Decrease")
  1075. ("f" nil "Finished" :exit t))
  1076. #+end_src
  1077. Increase the font size in buffers with =SPC t f=.
  1078. + Increase =j=
  1079. + Decrease =k=
  1080. + Finish =f=
  1081. #+begin_src emacs-lisp
  1082. (dotfiles/leader
  1083. "tf" '(hydra-text-scale/body :which-key "Font"))
  1084. #+end_src
  1085. *** Lines
  1086. Relative line numbers are important when using =VI= emulation keys. You can prefix most commands with a *number*, allowing you to jump up / down by a line count.
  1087. #+begin_example
  1088. 5:
  1089. 4:
  1090. 3:
  1091. 2:
  1092. 1:
  1093. 156: << CURRENT LINE >>
  1094. 1:
  1095. 2:
  1096. 3:
  1097. 4:
  1098. 5:
  1099. #+end_example
  1100. https://github.com/emacsmirror/linum-relative
  1101. + Integrate with ~display-line-numbers-mode~ for performance
  1102. #+begin_src emacs-lisp
  1103. (use-package linum-relative
  1104. :custom (linum-relative-backend 'display-line-numbers-mode)
  1105. :config (linum-relative-global-mode))
  1106. #+end_src
  1107. Add line numbers to the toggles behind =SPC t l=.
  1108. #+begin_src emacs-lisp
  1109. (dotfiles/leader
  1110. "tl" '(linum-relative-global-mode :which-key "Lines"))
  1111. #+end_src
  1112. https://github.com/Fanael/rainbow-delimiters
  1113. + Colourize nested parenthesis
  1114. #+begin_src emacs-lisp
  1115. (use-package rainbow-delimiters
  1116. :hook (prog-mode . rainbow-delimiters-mode))
  1117. #+end_src
  1118. *** Themes
  1119. #+ATTR_ORG: :width 420px
  1120. #+ATTR_HTML: :width 420px
  1121. #+ATTR_LATEX: :width 420px
  1122. [[./docs/images/what-is-emacs-customizable.gif]]
  1123. Cherry pick a few modules from =doom-emacs=. High quality and modern colour themes are provided in the [[https://github.com/hlissner/emacs-doom-themes][doom-themes]] package.
  1124. #+begin_src emacs-lisp
  1125. (use-package doom-themes
  1126. :init (load-theme 'doom-moonlight t))
  1127. #+end_src
  1128. [[https://github.com/seagle0128/doom-modeline][doom-modeline]] provides an elegant status bar / modeline.
  1129. #+begin_src emacs-lisp
  1130. (use-package doom-modeline
  1131. :custom (doom-modeline-height 16)
  1132. :config (doom-modeline-mode 1))
  1133. #+end_src
  1134. Load a theme with =SPC t t=.
  1135. #+begin_src emacs-lisp
  1136. (dotfiles/leader
  1137. "tt" '(counsel-load-theme t t :which-key "Theme"))
  1138. #+end_src
  1139. *** Pretty
  1140. Make programming buffers prettier with [[https://github.com/pretty-mode/pretty-mode][pretty-mode]], complimentary to the built in ~prettify-symbols-mode~.
  1141. #+begin_src emacs-lisp
  1142. (use-package pretty-mode
  1143. :hook (python-mode . turn-on-pretty-mode))
  1144. #+end_src
  1145. *** Ligatures
  1146. Enable font ligatures via [[https://github.com/jming422/fira-code-mode][fira-code-mode]], perform this action *only* when ~Fira Code~ is the current font.
  1147. #+begin_src emacs-lisp
  1148. (when (display-graphic-p)
  1149. (use-package fira-code-mode
  1150. :hook (prog-mode org-mode)))
  1151. #+end_src
  1152. Toggle global ligature mode with =SPC t g=.
  1153. #+begin_src emacs-lisp
  1154. (dotfiles/leader
  1155. "tg" '(global-fira-code-mode :which-key "Ligatures"))
  1156. #+end_src
  1157. *** Dashboard
  1158. #+ATTR_ORG: :width 420px
  1159. #+ATTR_HTML: :width 420px
  1160. #+ATTR_LATEX: :width 420px
  1161. [[./docs/images/desktop.png]]
  1162. Present a dashboard when first launching Emacs. Customize the buttons of the navigator:
  1163. + Brain @ http://localhost:8080
  1164. + Homepage @ https://chrishayward.xyz
  1165. + Athabasca @ https://login.athabascau.ca/cas/login
  1166. + Bookshelf @ https://online.vitalsource.com
  1167. #+begin_src emacs-lisp
  1168. (use-package dashboard
  1169. :custom (dashboard-center-content t)
  1170. (dashboard-set-init-info t)
  1171. (dashboard-set-file-icons t)
  1172. (dashboard-set-heading-icons t)
  1173. (dashboard-set-navigator t)
  1174. (dashboard-startup-banner 'logo)
  1175. (dashboard-projects-backend 'projectile)
  1176. (dashboard-items '((projects . 5) (recents . 5) (agenda . 10)))
  1177. (dashboard-navigator-buttons `(((,(all-the-icons-fileicon "brain" :height 1.1 :v-adjust 0.0)
  1178. "Brain" "Knowledge base"
  1179. (lambda (&rest _) (browse-url "http://localhost:8080"))))
  1180. ((,(all-the-icons-material "public" :height 1.1 :v-adjust 0.0)
  1181. "Homepage" "Personal website"
  1182. (lambda (&rest _) (browse-url "https://chrishayward.xyz"))))
  1183. ((,(all-the-icons-faicon "university" :height 1.1 :v-adjust 0.0)
  1184. "Athabasca" "Univeristy login"
  1185. (lambda (&rest _) (browse-url "https://login.athabascau.ca/cas/login"))))
  1186. ((,(all-the-icons-faicon "book" :height 1.1 :v-adjust 0.0)
  1187. "Bookshelf" "Vitalsource bookshelf"
  1188. (lambda (&rest _) (browse-url "https://online.vitalsource.com"))))))
  1189. :config (dashboard-setup-startup-hook))
  1190. #+end_src
  1191. When running in *daemon* mode, ensure that the dashboard is the initial buffer.
  1192. #+begin_src emacs-lisp
  1193. (setq initial-buffer-choice
  1194. (lambda ()
  1195. (get-buffer "*dashboard*")))
  1196. #+end_src