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.

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