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.

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