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.

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