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.

1161 lines
33 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
  1. #+TITLE: Dotfiles
  2. #+AUTHOR: Christopher James Hayward
  3. #+EMAIL: chris@chrishayward.xyz
  4. #+ROAM_KEY: https://github.com/chayward1/dotfiles
  5. #+begin_example
  6. ^^ @@@@@@@@@
  7. ^^ ^^ @@@@@@@@@@@@@@@
  8. @@@@@@@@@@@@@@@@@@ ^^
  9. @@@@@@@@@@@@@@@@@@@@
  10. ~~~~ ~~ ~~~~~ ~~~~~~~~ ~~ &&&&&&&&&&&&&&&&&&&& ~~~~~~~ ~~~~~~~~~~~ ~~~
  11. ~ ~~ ~ ~ ~~~~~~~~~~~~~~~~~~~~ ~ ~~ ~~ ~
  12. ~ ~~ ~~ ~~ ~~ ~~~~~~~~~~~~~ ~~~~ ~ ~~~ ~ ~~~ ~ ~~
  13. ~ ~~ ~ ~ ~~~~~~ ~~ ~~~ ~~ ~ ~~ ~~ ~
  14. ~ ~ ~ ~ ~ ~~ ~~~~~~ ~ ~~ ~ ~~
  15. ~ ~ ~ ~ ~~ ~ ~
  16. #+end_example
  17. Immutable GNU Emacs dotfiles, inspired by Doom, built for Liberty.
  18. + 100% Literate
  19. + 100% Immutable
  20. + 100% Reproducible
  21. * Init
  22. :PROPERTIES:
  23. :header-args: :tangle ~/.local/source/dotfiles/init.el
  24. :END:
  25. Load the host configuration.
  26. #+begin_src emacs-lisp
  27. (let ((host-file (concat "~/.local/source/dotfiles/hosts/" system-name ".el")))
  28. (when (file-exists-p host-file)
  29. (load-file host-file)))
  30. #+end_src
  31. Load the enabled modules.
  32. #+begin_src emacs-lisp
  33. (dolist (m dotfiles/modules)
  34. (let ((mod-file (concat "~/.local/source/dotfiles/modules/" (symbol-name m) ".el")))
  35. (when (file-exists-p mod-file)
  36. (load-file mod-file))))
  37. #+end_src
  38. * Hosts
  39. ** Example (Ubuntu)
  40. :PROPERTIES:
  41. :header-args: :tangle ~/.local/source/dotfiles/hosts/ubuntu.el
  42. :END:
  43. Set the browser to the flatpak currently installed.
  44. #+begin_src emacs-lisp
  45. (setenv "BROWSER" "flatpak run org.mozilla.firefox")
  46. #+end_src
  47. Add the modules you want to initialize to the ~dotfiles/modules~ variable.
  48. #+begin_src emacs-lisp
  49. (defvar dotfiles/modules '(core
  50. desktop
  51. writing
  52. projects
  53. interface))
  54. #+end_src
  55. Specify the cache directory.
  56. #+begin_src emacs-lisp
  57. (defvar dotfiles/cache "~/.cache/emacs")
  58. #+end_src
  59. Functionality like =completion= and =hints= can be delayed to avoid popups for common manuevers. Adjust this value to your personal taste.
  60. #+begin_src emacs-lisp
  61. (defvar dotfiles/idle 0.0)
  62. #+end_src
  63. Avoid the infamous *Emacs pinky* by binding =SPC= as a leader key, utilizing the thumb instead of the weaker pinky finger. You may change this value if you want to use something else.
  64. #+begin_src emacs-lisp
  65. (defvar dotfiles/leader-key "SPC")
  66. (defvar dotfiles/leader-key-global "C-SPC")
  67. #+end_src
  68. Define where the source repositories are stored, with most projects being relative from that directory.
  69. #+begin_src emacs-lisp
  70. (defvar dotfiles/src "~/.local/source/")
  71. #+end_src
  72. #+begin_src emacs-lisp
  73. (defvar dotfiles/brain (concat dotfiles/src "brain/"))
  74. (defvar dotfiles/notes (concat dotfiles/brain "notes/"))
  75. (defvar dotfiles/bib (concat dotfiles/brain "resources.bib"))
  76. #+end_src
  77. #+begin_src emacs-lisp
  78. (defvar dotfiles/secrets (concat dotfiles/src "secrets/"))
  79. (defvar dotfiles/passwords (concat dotfiles/src "passwords/"))
  80. #+end_src
  81. * Modules
  82. ** Core
  83. :PROPERTIES:
  84. :header-args: :tangle ~/.local/source/dotfiles/modules/core.el :results silent
  85. :END:
  86. 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.
  87. How can we solve this issue?
  88. Shortly after initialization, before most packages are loaded, we change the value to ~dotfiles/cache~. I elaborate more on the technique in my post [[https://chrishayward.xyz/posts/immutable_emacs/][Immutable Emacs]].
  89. #+begin_src emacs-lisp
  90. (setq user-emacs-directory dotfiles/cache)
  91. #+end_src
  92. Because this project uses version-control, we can disable more unwanted features:
  93. + Lock files
  94. + Backup files
  95. #+begin_src emacs-lisp
  96. (setq create-lockfiles nil
  97. make-backup-files nil)
  98. #+end_src
  99. *** Package management
  100. 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 where packages are sourced from.
  101. + Use the development branch
  102. + Integrate with ~use-package~
  103. Apply the configurations prior to bootstrapping the package manager, by setting (writing) to the variables that =straight= will ultimately read from.
  104. #+begin_src emacs-lisp
  105. (setq straight-repository-branch "develop"
  106. straight-use-package-by-default t)
  107. #+end_src
  108. Bootstrap the package manager, downloading, installing, or configuring depending on the state of the configuration. All packages are downloaded and built from source, and can be pinned to specific git commit hashes.
  109. #+begin_src emacs-lisp
  110. (defvar bootstrap-version)
  111. (let ((bootstrap-file
  112. (expand-file-name "straight/repos/straight.el/bootstrap.el" user-emacs-directory))
  113. (bootstrap-version 5))
  114. (unless (file-exists-p bootstrap-file)
  115. (with-current-buffer
  116. (url-retrieve-synchronously
  117. "https://raw.githubusercontent.com/raxod502/straight.el/develop/install.el"
  118. 'silent 'inhibit-cookies)
  119. (goto-char (point-max))
  120. (eval-print-last-sexp)))
  121. (load bootstrap-file nil 'nomessage))
  122. #+end_src
  123. Complete the integration with ~use-package~ by installing it with =straight=.
  124. #+begin_src emacs-lisp
  125. (straight-use-package 'use-package)
  126. #+end_src
  127. *** Hermetic evaluation
  128. Despite having our *stateful* and *immutable* configurations seperate, it's good practice to make efforts to reduce the trash created by Emacs.
  129. Install [[https://github.com/emacscollective/no-littering][no-littering]] to reduce the files created by Emacs.
  130. #+begin_src emacs-lisp
  131. (use-package no-littering)
  132. #+end_src
  133. Emacs' default user interface is horrendous, but with less than 10 lines of code we can change that.
  134. #+begin_src emacs-lisp
  135. (setq inhibit-startup-message t)
  136. (global-prettify-symbols-mode)
  137. (scroll-bar-mode -1)
  138. (menu-bar-mode -1)
  139. (tool-bar-mode -1)
  140. (tooltip-mode -1)
  141. #+end_src
  142. *** Literate programming
  143. *Organize your plain life in plain text*
  144. [[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.
  145. + [[https://orgmode.org/worg/org-contrib/babel/languages/index.html][Babel languages]]
  146. + [[https://orgmode.org/manual/Structure-Templates.html][Structure templates]]
  147. #+begin_src emacs-lisp
  148. (use-package org
  149. :hook
  150. (org-mode . (lambda ()
  151. (org-indent-mode)
  152. (visual-line-mode 1)
  153. (variable-pitch-mode 1)))
  154. :config
  155. (setq org-ellipsis " ▾"
  156. org-log-done 'time
  157. org-log-into-drawer t
  158. org-src-preserve-indentation t)
  159. (org-babel-do-load-languages
  160. 'org-babel-load-languages
  161. '((shell . t)
  162. (python . t)
  163. (emacs-lisp . t)))
  164. (require 'org-tempo)
  165. (add-to-list 'org-structure-template-alist '("s" . "src"))
  166. (add-to-list 'org-structure-template-alist '("q" . "quote"))
  167. (add-to-list 'org-structure-template-alist '("e" . "example"))
  168. (add-to-list 'org-structure-template-alist '("sh" . "src shell"))
  169. (add-to-list 'org-structure-template-alist '("py" . "src python"))
  170. (add-to-list 'org-structure-template-alist '("el" . "src emacs-lisp")))
  171. #+end_src
  172. #+begin_src emacs-lisp
  173. (defun dotfiles/tangle (dir)
  174. "Recursively tangle the Org files within a directory."
  175. (interactive)
  176. (let ((org-files (directory-files-recursively dir "org")))
  177. (dolist (f org-files)
  178. (org-babel-tangle-file f))))
  179. #+end_src
  180. *** Custom keybindings
  181. Make the =ESC= key quit (most) prompts, instead of the default =C-g=.
  182. #+begin_src emacs-lisp
  183. (global-set-key (kbd "<escape>") 'keyboard-escape-quit)
  184. #+end_src
  185. 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.
  186. #+begin_src emacs-lisp
  187. (use-package which-key
  188. :diminish which-key-mode
  189. :init (which-key-mode)
  190. :config (setq which-key-idle-delay dotfiles/idle))
  191. #+end_src
  192. 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.
  193. #+begin_src emacs-lisp
  194. (use-package general
  195. :config
  196. (general-create-definer dotfiles/leader
  197. :states '(normal motion)
  198. :keymaps 'override
  199. :prefix dotfiles/leader-key
  200. :global-prefix dotfiles/leader-key-global))
  201. #+end_src
  202. Use [[https://github.com/abo-abo/hydra][hydra]] for transient keybindings sharing a common prefix.
  203. #+begin_src emacs-lisp
  204. (use-package hydra)
  205. #+end_src
  206. After a few hour with =vim= I knew it was game over, I cannot even think of another way I would feel comfortable editing text. Luckily, there exist packages to emulate this within Emacs.
  207. https://evil.readthedocs.io/en/latest/index.html
  208. + Extendable VI layer for Emacs
  209. + Disable default keybindings
  210. #+begin_src emacs-lisp
  211. (use-package evil
  212. :init (setq evil-want-integration t
  213. evil-want-keybinding nil)
  214. :config (evil-mode 1))
  215. #+end_src
  216. https://github.com/emacs-evil/evil-collection
  217. + Community keybindings for =evil-mode=
  218. #+begin_src emacs-lisp
  219. (use-package evil-collection
  220. :after evil
  221. :config (evil-collection-init))
  222. #+end_src
  223. https://github.com/redguardtoo/evil-nerd-commenter
  224. + Toggle comments with =M-;=
  225. #+begin_src emacs-lisp
  226. (use-package evil-nerd-commenter
  227. :bind ("M-;" . evilnc-comment-or-uncomment-lines))
  228. #+end_src
  229. Again cherry picked from =Doom=, I want to continue utilizing the muscle memory I have developed from a year of mainlining the framework.
  230. + Close buffers with =SPC c=
  231. + Find files with =SPC . (period)=
  232. + Switch buffers with =SPC , (comma)=
  233. #+begin_src emacs-lisp
  234. (dotfiles/leader
  235. "." '(find-file :which-key "Files")
  236. "," '(switch-to-buffer :which-key "Buffers")
  237. "c" '(kill-buffer-and-window :which-key "Close"))
  238. #+end_src
  239. Run helper functions with =SPC h=.
  240. + Packages =p=
  241. + Variables =v=
  242. + Functions =f=
  243. #+begin_src emacs-lisp
  244. (dotfiles/leader
  245. "h" '(:ignore t :which-key "Help")
  246. "hp" '(describe-package :which-key "Package")
  247. "hv" '(describe-variable :which-key "Variable")
  248. "hf" '(describe-function :which-key "Function"))
  249. #+end_src
  250. Quit emacs with =SPC q=.
  251. + Saving =q=
  252. + Without =w=
  253. + Frame (daemon) =f=
  254. #+begin_src emacs-lisp
  255. (dotfiles/leader
  256. "q" '(:ignore t :which-key "Quit")
  257. "qq" '(save-buffers-kill-emacs :which-key "Save")
  258. "qw" '(kill-emacs :which-key "Now")
  259. "qf" '(delete-frame :which-key "Frame"))
  260. #+end_src
  261. Window management with =SPC w=.
  262. + Swap with =w=
  263. + Close with =c=
  264. + Motions with =h,j,k,l=
  265. + Split with =s + <MOTION>=
  266. #+begin_src emacs-lisp
  267. (dotfiles/leader
  268. "w" '(:ignore t :which-key "Window")
  269. "ww" '(window-swap-states :which-key "Swap")
  270. "wc" '(delete-window :which-key "Close")
  271. "wh" '(windmove-left :which-key "Left")
  272. "wj" '(windmove-down :which-key "Down")
  273. "wk" '(windmove-up :which-key "Up")
  274. "wl" '(windmove-right :which-key "Right")
  275. "ws" '(:ignore t :which-key "Split")
  276. "wsj" '(split-window-below :which-key "Down")
  277. "wsl" '(split-window-right :which-key "Right"))
  278. #+end_src
  279. Place runtime tweaks behind =SPC t=.
  280. #+begin_src emacs-lisp
  281. (dotfiles/leader
  282. "t" '(:ignore t :which-key "Tweaks"))
  283. #+end_src
  284. *** Version control
  285. Another hallmark feature is [[https://github.com/magit/magit][Magit]], a complete git porcelain within Emacs.
  286. #+begin_src emacs-lisp
  287. (use-package magit
  288. :custom (magit-display-buffer-function
  289. #'magit-display-buffer-same-window-except-diff-v1))
  290. #+end_src
  291. Work directly with github issues / pull requests using [[https://github.com/magit/forge][Forge]].
  292. + Requires a valid ~$GITHUB_TOKEN~
  293. #+begin_src emacs-lisp
  294. (use-package forge)
  295. #+end_src
  296. Open the *status* page for the current repository with =SPC g=.
  297. #+begin_src emacs-lisp
  298. (dotfiles/leader
  299. "g" '(magit-status :which-key "Magit"))
  300. #+end_src
  301. *** Terminal emulation
  302. While not a traditional terminal emulator, =eshell= provides me with all of the functionality I expect and require from one. Some users may be left wanting more, I would recommend they look into =vterm=.
  303. https://github.com/zwild/eshell-prompt-extras
  304. + Enable lambda shell prompt
  305. #+begin_src emacs-lisp
  306. (use-package eshell-prompt-extras
  307. :config (setq eshell-highlight-prompt nil
  308. eshell-prompt-function 'epe-theme-lambda))
  309. #+end_src
  310. Open an =eshell= buffer with =SPC e=.
  311. #+begin_src emacs-lisp
  312. (dotfiles/leader
  313. "e" '(eshell :which-key "Shell"))
  314. #+end_src
  315. *** File management
  316. Emacs' can feel more modern when icon-fonts are installed and prioritized. I feel that this makes navigation of folders much faster, given that file types may be quickly identified by their corresponding icons.
  317. https://github.com/domtronn/all-the-icons.el
  318. + Collects various icon fonts
  319. #+begin_src emacs-lisp
  320. (use-package all-the-icons)
  321. #+end_src
  322. https://github.com/jtbm37/all-the-icons-dired
  323. + Integration with dired
  324. #+begin_src emacs-lisp
  325. (use-package all-the-icons-dired
  326. :hook (dired-mode . all-the-icons-dired-mode))
  327. #+end_src
  328. When opening =dired=, I don't want to have to press =RET= twice to navigate to the current directory. This can be avoided with ~dired-jump~, included in the =dired-x= package shipped with =dired=.
  329. #+begin_src emacs-lisp
  330. (require 'dired-x)
  331. #+end_src
  332. By default =dired= will create a new buffer everytime you press =RET= over a directory. In my workflow this leads to many unwanted =dired= buffers that have to be cleaned up manually. [[https://github.com/crocket/dired-single][Dired-single]] lets us reuse the same dired buffer.
  333. + Move up a directory with =h=
  334. + Open a single buffer with =l=
  335. #+begin_src emacs-lisp
  336. (use-package dired-single
  337. :config
  338. (evil-collection-define-key 'normal 'dired-mode-map
  339. "h" 'dired-single-up-directory
  340. "l" 'dired-single-buffer))
  341. #+end_src
  342. Open a dired buffer with =SPC d=.
  343. #+begin_src emacs-lisp
  344. (dotfiles/leader
  345. "d" '(dired-jump :which-key "Dired"))
  346. #+end_src
  347. ** Desktop
  348. :PROPERTIES:
  349. :header-args: :tangle ~/.local/source/dotfiles/modules/desktop.el :results silent
  350. :END:
  351. 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=.
  352. #+begin_src emacs-lisp
  353. (defun dotfiles/run (command)
  354. "Run an external process."
  355. (interactive (list (read-shell-command "λ ")))
  356. (start-process-shell-command command nil command))
  357. #+end_src
  358. Some methods must be called and applied to the current call process in order to function correctly with Emacs hooks.
  359. #+begin_src emacs-lisp
  360. (defun dotfiles/run-in-background (command)
  361. (let ((command-parts (split-string command "[ ]+")))
  362. (apply #'call-process `(,(car command-parts) nil 0 nil ,@(cdr command-parts)))))
  363. #+end_src
  364. #+begin_src emacs-lisp
  365. (dotfiles/leader
  366. "x" '(dotfiles/run :which-key "Execute")
  367. "z" '(async-shell-command :which-key "Async"))
  368. #+end_src
  369. When the window manager first launches the ~init-hook~ will be called, this allows us to define some custom logic when it's initialized.
  370. + Display time and date
  371. + Display battery info (if available)
  372. 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.
  373. #+begin_src emacs-lisp
  374. (defun dotfiles/init-hook ()
  375. (exwm-workspace-switch-create 1)
  376. (setq display-time-and-date t)
  377. (display-battery-mode 1)
  378. (display-time-mode 1))
  379. #+end_src
  380. Using =autorandr= with pre configured profiles, switching screens (AKA hot plugging) is also handled through a hook.
  381. #+begin_src emacs-lisp
  382. (defun dotfiles/update-display ()
  383. (dotfiles/run-in-background "autorandr --change --force"))
  384. #+end_src
  385. Finally we configure the window manager.
  386. + Enable =randr= support
  387. Connect our custom hooks and configure the input keys, a custom layer for defining which keys are captured by Emacs, and which are passed through to =X= applications.
  388. + Pass through to Emacs
  389. + =M-x= to Emacs
  390. + =C-g= to Emacs
  391. + =C-SPC= to Emacs
  392. + Bindings with =S= (Super / Win)
  393. + Reset =S-r=
  394. + Launch =S-&=
  395. + Workspace =S-[1..9]=
  396. #+begin_src emacs-lisp
  397. (use-package exwm
  398. :config
  399. (require 'exwm-randr)
  400. (exwm-randr-enable)
  401. (add-hook 'exwm-init-hook #'dotfiles/init-hook)
  402. (add-hook 'exwm-randr-screen-change-hook #'dotfiles/update-display)
  403. (dotfiles/update-display)
  404. (setq exwm-input-prefix-keys
  405. '(?\M-x
  406. ?\C-g
  407. ?\C-\ )
  408. exwm-input-global-keys
  409. `(([?\s-r] . exwm-reset)
  410. ([?\s-&] . dotfiles/run)
  411. ,@(mapcar (lambda (i)
  412. `(,(kbd (format "s-%d" i)) .
  413. (lambda ()
  414. (interactive)
  415. (exwm-workspace-switch-create ,i))))
  416. (number-sequence 1 9))))
  417. (exwm-enable))
  418. #+end_src
  419. ** Writing
  420. :PROPERTIES:
  421. :header-args: :tangle ~/.local/source/dotfiles/modules/writing.el :results silent
  422. :END:
  423. I am using [[https://orgmode.org][Org-mode]] extensively for writing projects for different purposes. Improvements beyond what are required for my Literate Programming platform include:
  424. [[https://github.com/integral-dw/org-superstar-mode][Org-superstar-mode]] for making headline stars more *super*.
  425. #+begin_src emacs-lisp
  426. (use-package org-superstar
  427. :hook (org-mode . org-superstar-mode))
  428. #+end_src
  429. *** Mail
  430. #+begin_src emacs-lisp
  431. (use-package mu4e
  432. :load-path "/usr/share/emacs/site-lisp/mu4e"
  433. :config
  434. (setq mu4e-change-filenames-when-moving t
  435. mu4e-update-interval (* 5 60) ;; Every 5 minutes.
  436. mu4e-get-mail-command "mbsync -a"
  437. mu4e-maildir "~/.cache/mail"
  438. mu4e-compose-signature
  439. (concat "Chris Hayward\n"
  440. "https://chrishayward.xyz\n"))
  441. ;; Ensure plain text scales for all devices.
  442. (setq mu4e-compose-format-flowed t)
  443. ;; GPG signing key for outbound mail.
  444. (setq mml-secure-openpgp-signers '("37AB1CB72B741E478CA026D43025DCBD46F81C0F"))
  445. (add-hook 'message-send-hook 'mml-secure-message-sign-pgpmime)
  446. (setq message-send-mail-function 'smtpmail-send-it)
  447. ;; Configure mail account(s).
  448. (setq mu4e-contexts
  449. (list
  450. ;; Main
  451. ;; chris@chrishayward.xyz
  452. (make-mu4e-context
  453. :name "Main"
  454. :match-func
  455. (lambda (msg)
  456. (when msg
  457. (string-prefix-p "/Main" (mu4e-message-field msg :maildir))))
  458. :vars
  459. '((user-full-name . "Christopher James Hayward")
  460. (user-mail-address . "chris@chrishayward.xyz")
  461. (smtpmail-smtp-server . "mail.chrishayward.xyz")
  462. (smtpmail-smtp-service . 587)
  463. (smtpmail-stream-type . starttls))))))
  464. #+end_src
  465. #+begin_src emacs-lisp
  466. (dotfiles/leader
  467. "m" '(mu4e :which-key "Mail"))
  468. #+end_src
  469. *** Brain
  470. [[https://github.com/org-roam/org-roam][Org-roam]] is a rudimentary roam replica built on =Org mode=.
  471. #+begin_src emacs-lisp
  472. (use-package org-roam
  473. :hook (after-init . org-roam-mode)
  474. :custom (org-roam-directory dotfiles/brain))
  475. #+end_src
  476. [[https://github.com/org-roam/org-roam-server][Org-roam-server]] is a web application that visualizes the =Org roam= database, available when Emacs' running at [[http://localhost:8080][localhost:8080]].
  477. #+begin_src emacs-lisp
  478. (use-package org-roam-server
  479. :hook (org-roam-mode . org-roam-server-mode))
  480. #+end_src
  481. Configure keybindings behind =SPC r=.
  482. + Find with =f=
  483. + Buffer with =b=
  484. + Capture with =c=
  485. + Dailies with =d=
  486. #+begin_src emacs-lisp
  487. (dotfiles/leader
  488. "r" '(:ignore t :which-key "Roam")
  489. "rf" '(org-roam-find-file :which-key "Find")
  490. "rb" '(org-roam-buffer-toggle-display :which-key "Buffer")
  491. "rc" '(org-roam-capture :which-key "Capture")
  492. "rd" '(:ignore t :which-key "Dailies")
  493. "rdd" '(org-roam-dailies-find-date :which-key "Date")
  494. "rdt" '(org-roam-dailies-find-today :which-key "Today")
  495. "rdm" '(org-roam-dailies-find-tomorrow :which-key "Tomorrow")
  496. "rdy" '(org-roam-dailies-find-yesterday :which-key "Yesterday"))
  497. #+end_src
  498. Configure the default capture template for new topics.
  499. #+begin_src emacs-lisp
  500. (setq org-roam-capture-templates
  501. '(("d" "Default" plain (function org-roam-capture--get-point)
  502. "%?"
  503. :file-name "${slug}"
  504. :head "#+TITLE: ${title}\n"
  505. :unnarrowed t)))
  506. #+end_src
  507. Configure the default capture template for daily entries.
  508. #+begin_src emacs-lisp
  509. (setq org-roam-dailies-capture-templates
  510. '(("d" "Default" entry (function org-roam-capture--get-point)
  511. "* %?"
  512. :file-name "daily/%<%Y-%m-%d>"
  513. :head "#+TITLE: %<%Y-%m-%d>\n")))
  514. #+end_src
  515. *** Notes
  516. #+begin_src emacs-lisp
  517. (use-package org-noter
  518. :after org
  519. :config
  520. (setq org-noter-always-create-frame nil
  521. org-noter-notes-search-path dotfiles/notes))
  522. #+end_src
  523. #+begin_src emacs-lisp
  524. (use-package org-pdftools
  525. :hook (org-mode . org-pdftools-setup-link))
  526. #+end_src
  527. #+begin_src emacs-lisp
  528. (use-package org-noter-pdftools
  529. :after org-noter
  530. :config
  531. (with-eval-after-load 'pdf-annot
  532. (add-hook 'pdf-annot-active-handler-functions #'org-noter-pdftools-jump-to-note)))
  533. #+end_src
  534. #+begin_src emacs-lisp
  535. (setq bibtex-completion-notes-path dotfiles/notes
  536. bibtex-completion-bibliography dotfiles/bib
  537. bibtex-completion-pdf-field "file"
  538. bibtex-completion-notes-template-multiple-files
  539. (concat
  540. "#+TITLE: ${title}\n"
  541. "#+ROAM_KEY: cite:${=key=}\n"
  542. "#* TODO Notes\n"
  543. ":PROPERTIES:\n"
  544. ":CUSTOM_ID: ${=key}\n"
  545. ":NOTER_DOCUMENT: %(orb-process-file-field \"${=key=}\")\n"
  546. ":AUTHOR: ${author-abbrev}\n"
  547. ":JOURNAL: ${journaltitle}\n"
  548. ":DATE: ${date}\n"
  549. ":YEAR: ${year}\n"
  550. ":DOI: ${doi}\n"
  551. ":URL: ${url}\n"
  552. ":END:\n\n"))
  553. #+end_src
  554. #+begin_src emacs-lisp
  555. (use-package org-ref
  556. :config
  557. (setq org-ref-completion-library 'org-ref-helm-cite
  558. org-ref-get-pdf-filename-function 'org-ref-get-pdf-filename-helm-bibtex
  559. org-ref-default-bibliography dotfiles/bib
  560. org-ref-bibliography-notes dotfiles/notes
  561. org-ref-notes-directory dotfiles/notes
  562. org-ref-notes-function 'orb-edit-notes
  563. org-ref-note-title-format "* TODO %y - %t\n
  564. :PROPERTIES:\n
  565. :CUSTOM_ID: %k\n
  566. :NOTER_DOCUMENT: %F\n
  567. :ROAM_KEY: cite:%k\n
  568. :AUTHOR: %9a\n
  569. :JOURNAL: %j\n
  570. :YEAR: %y\n
  571. :VOLUME: %v\n
  572. :PAGES: %p\n
  573. :DOI: %D\n
  574. :URL: %U\n
  575. :END:\n\n"))
  576. #+end_src
  577. #+begin_src emacs-lisp
  578. (use-package org-roam-bibtex
  579. :after (org-roam)
  580. :hook (org-roam-mode . org-roam-bibtex-mode)
  581. :config
  582. (setq orb-preformat-keywords
  583. '("=key=" "title" "url" "file" "author-or-editor" "keywords")))
  584. #+end_src
  585. #+begin_src emacs-lisp
  586. (add-to-list 'org-roam-capture-templates
  587. '("n" "Notes" plain (function org-roam-capture--get-point)
  588. ""
  589. :file-name "notes/${slug}"
  590. :head "#+TITLE: ${=key=}: ${title}\n\n
  591. #+ROAM_KEY:${ref}\n\n* ${title}\n
  592. :PROPERTIES:\n
  593. :CUSTOM_ID: ${=key=}\n
  594. :URL: ${url}\n
  595. :AUTHOR: ${author-or-editor}\n
  596. :NOTER_DOCUMENT:%(orb-process-file-field \"${=key=}\")\n
  597. :NOTER_PAGE:\n
  598. :END:\n\n"))
  599. #+end_src
  600. *** Agenda
  601. Configure agenda sources.
  602. + Dailies ~~/.local/source/brain/daily/~
  603. + Secrets ~~/.local/source/secrets/org/~
  604. #+begin_src emacs-lisp
  605. (setq org-agenda-files '("~/.local/source/brain/daily/"
  606. "~/.local/source/secrets/org/"))
  607. #+end_src
  608. Open an agenda buffer with =SPC a=.
  609. #+begin_src emacs-lisp
  610. (dotfiles/leader
  611. "a" '(org-agenda :which-key "Agenda"))
  612. #+end_src
  613. *** Blogging
  614. I use [[https://gohugo.io][Hugo]] for my personal [[https://chrishayward.xyz][website]], which I write in =Org-mode= before compiling to =hugo-markdown=.
  615. [[https://github.com/kaushalmodi/ox-hugo][Ox-hugo]], configured for =one-post-per-file= is my technique for managing my blog.
  616. #+begin_src emacs-lisp
  617. (use-package ox-hugo
  618. :after ox)
  619. #+end_src
  620. Creaate a capture template for blog posts in the =posts= sub directory.
  621. #+begin_src emacs-lisp
  622. (add-to-list 'org-roam-capture-templates
  623. '("b" "Blogging" plain (function org-roam-capture--get-point)
  624. "%?"
  625. :file-name "posts/${slug}"
  626. :head "#+TITLE: ${title}\n
  627. #+HUGO_BASE_DIR: ~/.local/source/website\n
  628. #+HUGO_SECTION: posts\n"))
  629. #+end_src
  630. *** Screencasts
  631. Create screencasts with =one-frame-per-action= GIF recording via [[https://github.com/takaxp/emacs-gif-screencast][emacs-gif-screencast]].
  632. + Can be paused / resumed
  633. + High quality images
  634. + Optimized size
  635. It requires the installation of ~scrot~ and ~convert~ from the =ImageMagick= library.
  636. #+begin_src emacs-lisp
  637. (use-package gif-screencast
  638. :custom
  639. (gif-screencast-output-directory "~/.local/source/brain/screen/"))
  640. #+end_src
  641. Screencast controls behind =SPC s=.
  642. + Start / stop with =s=
  643. + Pause with =t=
  644. #+begin_src emacs-lisp
  645. (dotfiles/leader
  646. "s" '(:ignore t :which-key "Screencast")
  647. "ss" '(gif-screencast-start-or-stop :which-key "Start / Stop")
  648. "sp" '(gif-screencast-toggle-pause :which-key "Pause"))
  649. #+end_src
  650. *** Presentations
  651. Produce high quality presentations that work anywhere with =HTML/JS= and the [[https://revealjs.com][Reveal.js]] package.
  652. [[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=.
  653. #+begin_src emacs-lisp
  654. (use-package ox-reveal
  655. :after ox
  656. :custom (org-reveal-root "https://cdn.jsdelivr.net/reveal.js/3.9.2/"))
  657. #+end_src
  658. Create a capture template for presentations stored in the =slides= sub directory.
  659. #+begin_src emacs-lisp
  660. (add-to-list 'org-roam-capture-templates
  661. '("p" "Presentation" plain (function org-roam-capture--get-point)
  662. "%?"
  663. :file-name "slides/${slug}"
  664. :head "#+TITLE: ${title}\n"))
  665. #+end_src
  666. ** Projects
  667. :PROPERTIES:
  668. :header-args: :tangle ~/.local/source/dotfiles/modules/projects.el :results silent
  669. :END:
  670. An IDE like experience (or better) can be achieved in Emacs using two *Microsoft* open source initiatives.
  671. Turn Emacs into an *IDE* (or better) with the [[https://microsoft.github.io/language-server-protocol/][Language Server Protocol]], an open source initiative from *Microsoft* for the *VSCode* editor.
  672. [[https://emacs-lsp.github.io/lsp-mode/][Lsp-mode]] brings support for language servers into Emacs.
  673. #+begin_src emacs-lisp
  674. (use-package lsp-mode
  675. :custom (gc-cons-threshold 1000000000)
  676. (lsp-idle-delay 0.500))
  677. #+end_src
  678. https://emacs-lsp.github.io/lsp-ui/
  679. + UI improvements for =lsp-mode=
  680. #+begin_src emacs-lisp
  681. (use-package lsp-ui
  682. :custom (lsp-ui-doc-position 'at-point)
  683. (lsp-ui-doc-delay 0.500))
  684. #+end_src
  685. *** Management
  686. 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.
  687. #+begin_src emacs-lisp
  688. (use-package projectile
  689. :config
  690. (setq projectile-project-search-path '("~/.local/source"))
  691. (projectile-mode))
  692. #+end_src
  693. *** Passwords
  694. 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.
  695. #+begin_src emacs-lisp
  696. (use-package password-store
  697. :custom (password-store-dir dotfiles/passwords))
  698. #+end_src
  699. Configure keybindings behind =SPC p=.
  700. + Copy with =p=
  701. + Rename with =r=
  702. + Generate with =g=
  703. #+begin_src emacs-lisp
  704. (dotfiles/leader
  705. "p" '(:ignore t :which-key "Passwords")
  706. "pp" '(password-store-copy :which-key "Copy")
  707. "pr" '(password-store-rename :which-key "Rename")
  708. "pg" '(password-store-generate :which-key "Generate"))
  709. #+end_src
  710. *** Debugging
  711. Handled through the [[https://microsoft.github.io/debug-adapter-protocol/][Debug Adapter Protocol]], an open source initiative from *Microsoft* for the *VSCode* editor.
  712. [[https://emacs-lsp.github.io/dap-mode/][Dap-mode]] adds support for the protocol to Emacs.
  713. #+begin_src emacs-lisp
  714. (use-package dap-mode)
  715. #+end_src
  716. *** Completion
  717. Text completion framework via =company= aka *Complete Anything*.
  718. http://company-mode.github.io/
  719. + Integrate with =lsp-mode=
  720. #+begin_src emacs-lisp
  721. (use-package company)
  722. (use-package company-lsp)
  723. #+end_src
  724. *** Languages
  725. Support for individual languages are implemented here.
  726. **** C/C++
  727. Full *IDE* experience for Python within Emacs.
  728. + Completion, jumps via =lsp-mode=
  729. + Debugging via =dap-mode=
  730. Install the =ccls= language server.
  731. + https://github.com/MaskRay/ccls
  732. #+begin_src emacs-lisp
  733. (use-package ccls
  734. :hook ((c-mode c++-mode objc-mode cuda-mode) .
  735. (lambda () (require 'ccls) (lsp))))
  736. #+end_src
  737. **** Python
  738. Full *IDE* experience for Python within Emacs.
  739. + Completion, jumps via =lsp-mode=
  740. + Debugging via =dap-mode=
  741. Install the =pyls= language server.
  742. #+begin_src shell :tangle no
  743. pip install --user "python-language-server[all]"
  744. #+end_src
  745. https://www.emacswiki.org/emacs/PythonProgrammingInEmacs
  746. + Built in mode
  747. #+begin_src emacs-lisp
  748. (use-package python-mode
  749. :hook (python-mode . lsp)
  750. :config (require 'dap-python)
  751. :custom (python-shell-interpreter "python3") ;; Required if "python" is not python 3.
  752. (dap-python-executable "python3") ;; Same as above.
  753. (dap-python-debugger 'debugpy))
  754. #+end_src
  755. **** Go
  756. Full *IDE* experience for Rust within Emacs.
  757. + Completion via =lsp-mode=
  758. + Debugging via =dap-mode=
  759. Install the =gopls= language server.
  760. #+begin_src sh :tangle no
  761. GO111MODULE=on go get golang.org/x/tools/gopls@latest
  762. #+end_src
  763. Set the ~GOPATH~ environment variable prior to loading, this allows us to change the default value of ~$HOME/go~ to ~$HOME.go~.
  764. #+begin_src emacs-lisp
  765. (setenv "GOPATH" (concat (getenv "HOME") "/.go/"))
  766. #+end_src
  767. #+begin_src emacs-lisp
  768. (use-package go-mode
  769. :hook (go-mode . lsp))
  770. #+end_src
  771. Apply some custom behaviour before saving:
  772. + Format buffer
  773. + Organize imports
  774. #+begin_src emacs-lisp
  775. (defun dotfiles/go-hook ()
  776. (add-hook 'before-save-hook #'lsp-format-buffer t t)
  777. (add-hook 'before-save-hook #'lsp-organize-imports t t))
  778. #+end_src
  779. #+begin_src emacs-lisp
  780. (add-hook 'go-mode-hook #'dotfiles/go-hook)
  781. #+end_src
  782. ** Interface
  783. :PROPERTIES:
  784. :header-args: :tangle ~/.local/source/dotfiles/modules/interface.el :results silent
  785. :END:
  786. *Bring Emacs out of the eighties*
  787. *** Fonts
  788. 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.
  789. #+begin_src emacs-lisp
  790. (defvar dotfiles/font "Fira Code")
  791. (defvar dotfiles/font-size 96)
  792. #+end_src
  793. Write out to all *3* of Emacs' default font faces.
  794. #+begin_src emacs-lisp
  795. (set-face-attribute 'default nil :font dotfiles/font :height dotfiles/font-size)
  796. (set-face-attribute 'fixed-pitch nil :font dotfiles/font :height dotfiles/font-size)
  797. (set-face-attribute 'variable-pitch nil :font dotfiles/font :height dotfiles/font-size)
  798. #+end_src
  799. Define a transient keybinding for scaling the text.
  800. #+begin_src emacs-lisp
  801. (defhydra hydra-text-scale (:timeout 4)
  802. "Scale"
  803. ("j" text-scale-increase "Increase")
  804. ("k" text-scale-decrease "Decrease")
  805. ("f" nil "Finished" :exit t))
  806. #+end_src
  807. Increase the font size in buffers with =SPC t f=.
  808. + Increase =j=
  809. + Decrease =k=
  810. + Finish =f=
  811. #+begin_src emacs-lisp
  812. (dotfiles/leader
  813. "tf" '(hydra-text-scale/body :which-key "Font"))
  814. #+end_src
  815. *** Lines
  816. 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.
  817. #+begin_example
  818. 5:
  819. 4:
  820. 3:
  821. 2:
  822. 1:
  823. 156: << CURRENT LINE >>
  824. 1:
  825. 2:
  826. 3:
  827. 4:
  828. 5:
  829. #+end_example
  830. https://github.com/emacsmirror/linum-relative
  831. + Integrate with ~display-line-numbers-mode~ for performance
  832. #+begin_src emacs-lisp
  833. (use-package linum-relative
  834. :init (setq linum-relative-backend
  835. 'display-line-numbers-mode)
  836. :config (linum-relative-global-mode))
  837. #+end_src
  838. Add line numbers to the toggles behind =SPC t l=.
  839. #+begin_src emacs-lisp
  840. (dotfiles/leader
  841. "tl" '(linum-relative-global-mode :which-key "Lines"))
  842. #+end_src
  843. https://github.com/Fanael/rainbow-delimiters
  844. + Colourize nested parenthesis
  845. #+begin_src emacs-lisp
  846. (use-package rainbow-delimiters
  847. :hook (prog-mode . rainbow-delimiters-mode))
  848. #+end_src
  849. *** Themes
  850. 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.
  851. #+begin_src emacs-lisp
  852. (use-package doom-themes
  853. :init (load-theme 'doom-moonlight t))
  854. #+end_src
  855. [[https://github.com/seagle0128/doom-modeline][doom-modeline]] provides an elegant status bar / modeline.
  856. #+begin_src emacs-lisp
  857. (use-package doom-modeline
  858. :init (doom-modeline-mode 1)
  859. :custom ((doom-modeline-height 16)))
  860. #+end_src
  861. Load a theme with =SPC t t=.
  862. #+begin_src emacs-lisp
  863. (dotfiles/leader
  864. "tt" '(load-theme t t :which-key "Theme"))
  865. #+end_src
  866. *** Ligatures
  867. Enable font ligatures via [[https://github.com/jming422/fira-code-mode][fira-code-mode]], perform this action *only* when ~Fira Code~ is set as the current font.
  868. #+begin_src emacs-lisp
  869. ;; (use-package fira-code-mode
  870. ;; :config
  871. ;; (global-fira-code-mode))
  872. #+end_src
  873. #+begin_src emacs-lisp
  874. ;; (use-package fira-code-mode
  875. ;; :hook prog-mode)
  876. #+end_src
  877. *** Dashboard
  878. Present a dashboard when first launching Emacs.
  879. #+begin_src emacs-lisp
  880. (use-package dashboard
  881. :config
  882. (setq dashboard-center-content t
  883. dashboard-set-init-info t
  884. dashboard-set-file-icons t
  885. dashboard-set-heading-icons t
  886. dashboard-startup-banner 'logo
  887. dashboard-projects-backend 'projectile
  888. dashboard-items '((projects . 5)
  889. (recents . 5)
  890. (agenda . 5 )))
  891. (dashboard-setup-startup-hook))
  892. #+end_src
  893. When running in *daemon* mode, ensure that the dashboard is the initial buffer.
  894. #+begin_src emacs-lisp
  895. (setq initial-buffer-choice
  896. (lambda ()
  897. (get-buffer "*dashboard*")))
  898. #+end_src