config.el 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346
  1. (setq user-full-name "Colin Powell"
  2. user-mail-address "colin@unbl.ink")
  3. ;;(setq ivy-read-action-function #'ivy-hydra-read-action)
  4. (defun file-notify-rm-all-watches ()
  5. "Remove all existing file notification watches from Emacs."
  6. (interactive)
  7. (maphash
  8. (lambda (key _value)
  9. (file-notify-rm-watch key))
  10. file-notify-descriptors))
  11. (setq doom-theme 'moe-dark
  12. doom-font (font-spec :family "IBM Plex Mono" :size 13 :weight 'regular)
  13. doom-big-font (font-spec :family "IBM Plex Mono" :size 17 :weight 'regular)
  14. doom-variable-pitch-font (font-spec :family "Overpass" :size 12))
  15. ;; Applies to current frame
  16. ;(set-frame-parameter nil 'internal-border-width 10) ; applies to the current frame
  17. ;; If we create new frames (via emacsclient) this will do the trick
  18. ;(add-to-list 'default-frame-alist '(internal-border-width . 10))
  19. (nyan-mode) ;; progress in the form of a rainbow cat.
  20. (add-hook 'after-init-hook #'global-emojify-mode) ;; emojis?!
  21. (add-hook 'prog-mode-hook #'goto-address-mode) ;; linify links!
  22. (setq eww-search-prefix "https://search.unbl.ink/?q=")
  23. (map! ;; Easier window movement
  24. :n "C-h" 'evil-window-left
  25. :n "C-j" 'evil-window-down
  26. :n "C-k" 'evil-window-up
  27. :n "C-l" 'evil-window-right
  28. (:map evil-treemacs-state-map
  29. "C-h" 'evil-window-left
  30. "C-l" 'evil-window-right)
  31. :leader
  32. (:prefix "f"
  33. :desc "Find file in dotfiles" "t" #'+hlissner/find-in-dotfiles
  34. :desc "Browse dotfiles" "T" #'+hlissner/browse-dotfiles)
  35. (:prefix "o"
  36. :desc "(H)ckrnews" "H" #'hackernews
  37. :desc "(R)SS" "R" #'=rss
  38. :desc "(M)ail" "M" #'=notmuch
  39. :desc "(L)obste.rs" "L" #'ivy-lobsters)
  40. (:prefix "b"
  41. :desc "Black format buffer" "f" #'blacken-buffer
  42. :desc "isort buffer" "I" #'py-isort-buffer
  43. :desc "Links in buffer" "l" #'ace-link-org)
  44. (:prefix "s"
  45. :desc "Copy link hints" "c" #'link-hint-copy-link
  46. :desc "Search the web" "w" #'web-search
  47. :desc "Goto URL in eww" "u" #'eww-browse-url
  48. :desc "Search in eww" "3" #'eww-search-words
  49. :desc "Search all the things" "g" #'deadgrep))
  50. (setq libmpdel-hostname "mpd.play.unbl.ink")
  51. (defun mpdel-playlist-play ()
  52. "Start playing the song at point."
  53. (interactive)
  54. (if (derived-mode-p 'mpdel-playlist-current-playlist-mode)
  55. (libmpdel-play-song (navigel-entity-at-point))
  56. (mpdel-core-insert-current-playlist)))
  57. (map! :leader
  58. (:prefix "-"
  59. :desc "MPD Open playlist" "-" #'mpdel-playlist-open
  60. :desc "MPD Remove at point" "d" #'mpdel-playlist-delete
  61. :desc "MPD Start at point" "s" #'mpdel-playlist-play
  62. :desc "MPD Next track" "n" #'libmpdel-playback-next
  63. :desc "MPD Previous track" "p" #'libmpdel-playback-previous))
  64. (setq elfeed-protocol-fever-maxsize 100)
  65. (setq elfeed-feeds '(("fever+https://secstate@rss.unbl.ink"
  66. :api-url "https://rss.unbl.ink/fever/"
  67. :password "password"
  68. :autotags '(("rss.unbl.ink")))))
  69. ;(setq elfeed-protocol-log-trace t)
  70. (setq elfeed-protocol-fever-maxsize 50)
  71. ;(setq elfeed-log-level 'debug)
  72. (elfeed-protocol-enable)
  73. (map! :leader
  74. (:prefix "r"
  75. :desc "Open Elfeed" "r" #'elfeed
  76. :desc "Update Elfeed" "u" #'elfeed-update))
  77. ;; Schedule feed update for every 15 minutes
  78. (run-at-time 300 300
  79. (lambda () (when (= elfeed-curl-queue-active 0)
  80. (elfeed-update))))
  81. ;;;;; Database auto-save
  82. ;; Save elfeed db automatically, because if Emacs crashes or is killed (which happens to me
  83. ;; occasionally, especially since I develop packages in a single instance), we'd lose the db
  84. ;; updates not saved.
  85. (unless (cl-loop for timer in timer-idle-list
  86. thereis (equal (aref timer 5) #'elfeed-db-save))
  87. (run-with-idle-timer 400 'repeat #'elfeed-db-save))
  88. (setq elfeed-search-filter "@2-days-ago +unread")
  89. (defun elfeed-search-format-date (date)
  90. (format-time-string "%Y-%m-%d %H:%M" (seconds-to-time date)))
  91. ; Serif font in Elfeed
  92. (add-hook! 'elfeed-mode-hook 'variable-pitch-mode)
  93. (add-hook! 'elfeed-show-mode-hook (text-scale-set 1.2))
  94. (defun unfill-paragraph ()
  95. "Takes a multi-line paragraph and makes it into a single line of text."
  96. (interactive)
  97. (let ((fill-column (point-max)))
  98. (fill-paragraph nil)))
  99. (define-key global-map "\M-z" 'unfill-paragraph)
  100. (flycheck-define-checker vale
  101. "A checker for prose"
  102. :command ("vale" "--output" "line"
  103. source)
  104. :standard-input nil
  105. :error-patterns
  106. ((error line-start (file-name) ":" line ":" column ":" (id (one-or-more (not (any ":")))) ":" (message) line-end))
  107. :modes (markdown-mode org-mode text-mode)
  108. )
  109. (add-to-list 'flycheck-checkers 'vale 'append)
  110. (setq +format-on-save-enabled-modes
  111. '(not emacs-lisp-mode ; elisp's mechanisms are good enough
  112. sql-mode ; sqlformat is currently broken
  113. tex-mode ; latexindent is broken
  114. org-mode
  115. html-mode
  116. latex-mode))
  117. (load! "+agenda-fix")
  118. (defun vulpea-agenda-files-update (&rest _)
  119. (setq org-agenda-files vulpea-project-files))
  120. (advice-add 'org-agenda :before #'vulpea-agenda-files-update)
  121. (advice-add 'org-todo-list :before #'vulpea-agenda-files-update)
  122. (add-hook 'org-mode-hook #'doom-disable-line-numbers-h)
  123. (after! org
  124. (setq org-directory (expand-file-name "~/var/org/")
  125. org-ellipsis "…"
  126. org-image-actual-width '(600)
  127. org-log-done 'time
  128. org-fontify-quote-and-verse-blocks t
  129. org-agenda-dim-blocked-tasks nil
  130. org-pretty-entities t
  131. org-fancy-priorities-list '("🅰" "🅱" "🅲" "🅳" "🅴")
  132. org-modules '(ol-eshell
  133. ol-notmuch
  134. ob-eval
  135. ob-exp
  136. ob-http
  137. org-id)))
  138. ;; Refiling
  139. (setq org-refile-targets '((vulpea-project-files :maxlevel . 9)))
  140. (setq org-outline-path-complete-in-steps nil) ; Refile in a single go
  141. (setq org-refile-use-outline-path t) ; Show full paths for refiling
  142. (setq +inbox-file "~/var/org/index.org")
  143. (defun +open-inbox-file ()
  144. (interactive)
  145. "Opens the inbox file"
  146. (find-file +inbox-file))
  147. (map!
  148. :leader
  149. :desc "Open inbox" "I" #'+open-inbox-file
  150. :desc "Open today" "d" #'org-roam-dailies-goto-today
  151. :desc "Save all org buffers" "A" #'org-save-all-org-buffers)
  152. (setq org-roam-directory "~/var/org/")
  153. (setq org-roam-dailies-directory "dailies")
  154. (require 'justify-kp)
  155. ;(setq nov-text-width t)
  156. (setq nov-text-width 100)
  157. (defun my-nov-window-configuration-change-hook ()
  158. (my-nov-post-html-render-hook)
  159. (remove-hook 'window-configuration-change-hook
  160. 'my-nov-window-configuration-change-hook
  161. t))
  162. (defun my-nov-post-html-render-hook ()
  163. (if (get-buffer-window)
  164. (let ((max-width (pj-line-width))
  165. buffer-read-only)
  166. (save-excursion
  167. (goto-char (point-min))
  168. (while (not (eobp))
  169. (when (not (looking-at "^[[:space:]]*$"))
  170. (goto-char (line-end-position))
  171. (when (> (shr-pixel-column) max-width)
  172. (goto-char (line-beginning-position))
  173. (pj-justify)))
  174. (forward-line 1))))
  175. (add-hook 'window-configuration-change-hook
  176. 'my-nov-window-configuration-change-hook
  177. nil t)))
  178. (add-hook 'nov-post-html-render-hook 'my-nov-post-html-render-hook)
  179. (defun my-nov-font-setup ()
  180. (face-remap-add-relative 'variable-pitch :family "Noto Serif Regular"
  181. :height 1.0
  182. :size 16))
  183. (add-hook 'nov-mode-hook 'my-nov-font-setup)
  184. (add-to-list 'auto-mode-alist '("\\.epub\\'" . nov-mode))
  185. ;(add-hook 'nov-mode-hook 'variable-pitch-mode)
  186. (setq mm-text-html-renderer 'w3m)
  187. (setq w3m-fill-column 88)
  188. (setq message-kill-buffer-on-exit t)
  189. (setq message-auto-save-directory "~/Mail/colin@unbl.ink/Drafts/")
  190. (setq message-directory "~/Mail/colin@unbl.ink/")
  191. ;; sendmail-program "/usr/local/bin/msmtpq" <--- this doesn't work as advertised right now
  192. (setq send-mail-function 'sendmail-send-it
  193. sendmail-program "/usr/local/bin/msmtp"
  194. mail-specify-envelope-from t
  195. message-sendmail-f-is-evil t
  196. message-sendmail-envelope-from 'header
  197. message-sendmail-extra-arguments '("--read-envelope-from")
  198. mail-envelope-from 'header)
  199. (setq notmuch-saved-searches '((:name "inbox" :query "tag:inbox" :key "i")
  200. (:name "unread" :query "tag:inbox and tag:unread" :key "u")
  201. (:name "jira" :query "tag:jira and date:yesterday..today" :key "j")
  202. (:name "github" :query "tag:github and date:yesterday..today" :key "g")))
  203. (after! notmuch
  204. (set-popup-rule! "^\\*notmuch*" :ignore t)
  205. )
  206. (map! :leader
  207. (:prefix "e"
  208. :desc "(s)end queued mail" "s" #'smtpmail-send-queued-mail
  209. :desc "Open (i)nbox" "i" #'=notmuch
  210. :desc "Open (n)otmuch" "n" #'notmuch
  211. :desc "(C)ompose mail" "c" #'notmuch-mua-new-mail))
  212. (after! eshell
  213. (set-eshell-alias!
  214. "djtest" "DJANGO_SETTINGS_MODULE=ff.settings.ci python manage.py test $*"
  215. "djpytest" "DJANGO_SETTINGS_MODULE=ff.settings.ci pytest --reuse-db --black --flake8 --isort --durations=3 $*"
  216. "ffsh" "python ~/src/github.com/15five/fifteen5/manage.py shell_plus"
  217. "ffdev" "ssh dev-ff.local "
  218. "f" "(other-window 1) && find-file $1"
  219. "l" "ls -lh"
  220. "d" "dired $1"
  221. "gl" "(call-interactively 'magit-log-current)"
  222. "gs" "magit-status"
  223. "gc" "magit-commit"))
  224. (setq lsp-lens-enable 1
  225. lsp-ui-sideline-enable 1
  226. lsp-enable-links 1
  227. lsp-headerline-breadcrumb-enable 1
  228. lsp-modeline-code-actions-enable 1
  229. lsp-modeline-diagnostics-enable 1
  230. lsp-completion-show-detail 1
  231. lsp-file-watch-threshold nil
  232. )
  233. (use-package lsp-mode
  234. :commands lsp
  235. :diminish lsp-mode
  236. :hook
  237. (elixir-mode . lsp)
  238. :init
  239. (add-to-list 'exec-path "~/.emacs.d/var/elixir-ls"))
  240. (setq mastodon-instance-url "https://fosstodon.org"
  241. mastodon-active-user "colin@unbl.ink")
  242. (map! :leader
  243. (:prefix "="
  244. :desc "Open mastodon" "=" #'mastodon
  245. :desc "Update Mastodon timeline" "u" #'mastodon-tl--update
  246. :desc "More Mastodon timeline" "m" #'mastodon-tl--more
  247. :desc "Toot to Mastodon" "t" #'mastodon-toot))
  248. (load! "beancount")
  249. (require 'beancount)
  250. (add-to-list 'auto-mode-alist '("\\.beancount\\'" . beancount-mode))
  251. (define-derived-mode
  252. pandoc-view-mode
  253. markdown-mode
  254. "pandoc-view-mode"
  255. "View pandoc processing of docx file using markdown mode."
  256. (erase-buffer)
  257. (let* ((pandoc (executable-find "pandoc")))
  258. (insert (shell-command-to-string
  259. (concat pandoc " --wrap=none " (shell-quote-argument (buffer-file-name)) " -t markdown"))))
  260. (not-modified)
  261. (read-only-mode t))
  262. (add-to-list 'auto-mode-alist '("\\.docx\\'" . pandoc-view-mode))
  263. (after! magit
  264. (magit-wip-after-save-mode t)
  265. (magit-wip-after-apply-mode t)
  266. (setq magit-save-repository-buffers 'dontask
  267. magit-repository-directories '(("~/src/" . 3)
  268. ("~/.dotfiles/" . 0))
  269. magit-popup-display-buffer-action nil ;; Not sure why this is here, wonder what it does
  270. magit-display-file-buffer-function #'switch-to-buffer-other-window
  271. magithub-clone-default-directory "~/src" ;; I want my stuff to clone to ~/projects
  272. magithub-preferred-remote-method 'ssh_url)) ;; HTTPS cloning is awful, i authenticate with ssh keys.
  273. ; Show gravatars in magit
  274. (setq magit-revision-show-gravatars '("^Author: " . "^Commit: "))
  275. (when (require 'openwith nil 'noerror)
  276. (setq openwith-associations
  277. (list
  278. (list (openwith-make-extension-regexp
  279. '("mpg" "mpeg" "mp3" "mp4"
  280. "avi" "wmv" "wav" "mov" "flv"
  281. "ogm" "ogg" "mkv"))
  282. "vlc"
  283. '(file))
  284. (list (openwith-make-extension-regexp
  285. '("pdf" "ps" "ps.gz" "dvi"))
  286. "zathura"
  287. '(file))
  288. ))
  289. (openwith-mode 1))
  290. (setq org-reveal-root "file:///path-to-reveal.js")
  291. (setq org-reveal-title-slide nil)