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.

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