Files
opalfiles/.config/doom/config.el

407 lines
14 KiB
EmacsLisp
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
;;; config.el -*- lexical-binding: t; -*-
;; Clean up starting screen
;; (setq fancy-splash-image "~/.config/doom/splash.png")
(remove-hook '+doom-dashboard-functions #'doom-dashboard-widget-shortmenu)
(remove-hook '+doom-dashboard-functions #'doom-dashboard-widget-banner)
(remove-hook '+doom-dashboard-functions #'doom-dashboard-widget-footer)
(remove-hook '+doom-dashboard-functions #'doom-dashboard-widget-loaded)
(add-hook! '+doom-dashboard-mode-hook (hide-mode-line-mode 1) (hl-line-mode -1))
(setq-hook! '+doom-dashboard-mode-hook evil-normal-state-cursor (list nil))
;; Inherit SSH_AUTH_SOCK cuz emacs daint
(use-package exec-path-from-shell
:ensure t
:config
(exec-path-from-shell-initialize)
(exec-path-from-shell-copy-envs '("SSH_AUTH_SOCK" "SSH_AGENT_PID")))
(setq vc-ignore-dir-regexp
(format "\\(%s\\)\\|\\(%s\\)"
vc-ignore-dir-regexp
tramp-file-name-regexp))
;; Set name & e-mail
(setq user-full-name "opal"
user-mail-address "ry.orlando@proton.me")
(setq vterm-shell "/bin/zsh")
;; Theme & background color
(load-theme 'doom-gruvbox t)
;;(set-face-background 'default "#E8D8B0")
;; Lockfiles
(setq create-lockfiles nil)
;; Remove line numbers from specific modes
(dolist (mode '(org-mode-hook
shell-mode-hook
eshell-mode-hook))
(add-hook mode (lambda () (display-line-numbers-mode 0))))
;; Font Config
(setq doom-font (font-spec :family "Victor Mono" :size 22 :weight 'medium)
doom-variable-pitch-font (font-spec :family "Victor Mono" :size 22 :weight 'medium :slant 'italic))
(defun opal/org-font-setup ()
;; Replace list hyphen with dot
(font-lock-add-keywords 'org-mode
'(("^ *\\([-]\\) "
(0 (prog1 () (compose-region (match-beginning 1) (match-end 1)
""))))))
;; Set heading sizes only
(dolist (face '((org-level-1 . 1.2)
(org-level-2 . 1.1)
(org-level-3 . 1.05)
(org-level-4 . 1.0)
(org-level-5 . 1.1)
(org-level-6 . 1.1)
(org-level-7 . 1.1)
(org-level-8 . 1.1)))
(set-face-attribute (car face) nil :height (cdr face)))
;; Ensure that all agenda items inherit default
(custom-set-faces
'(org-agenda-date-today ((t (:inherit default :weight bold))))
'(org-agenda-date ((t (:inherit default))))
'(org-agenda-date-weekend ((t (:inherit default :weight bold))))
'(org-agenda-done ((t (:inherit default :strike-through t))))
'(org-agenda-dimmed-todo-face ((t (:inherit default))))
'(org-agenda-structure ((t (:inherit default))))
'(org-scheduled ((t (:inherit default))))
'(org-scheduled-today ((t (:inherit default))))
'(org-scheduled-previously ((t (:inherit default))))
'(org-upcoming-deadline ((t (:inherit default))))
'(org-deadline-announce ((t (:inherit default))))
'(org-time-grid ((t (:inherit default))))))
(defun opal/org-mode-setup ()
(org-indent-mode)
(visual-line-mode 1)
(variable-pitch-mode 1))
(use-package org
:commands (org-capture org-agenda)
:hook (org-mode . opal/org-mode-setup)
:config
(setq org-ellipsis "")
(setq org-agenda-start-with-log-mode t)
(setq org-log-done 'time)
(setq org-log-into-drawer t)
;;(setq org-startup-folded t)
(setq org-indent-indentation-per-level 2)
(setq org-hide-emphasis-markers t)
(setq org-agenda-files (directory-files-recursively "~/sync/org/agenda/" "\\.org$"))
(setq org-agenda-todo-ignore-scheduled 'future)
(require 'org-habit)
(add-to-list 'org-modules 'org-habit)
(setq org-habit-graph-column 60)
(setq org-todo-keywords
'((sequence "ALRT(a)" "EASY(e)" "PROG(p)" "NEXT(n)"
"TODO(t)" "WAIT(w)" "|" "DONE(d)")))
(setq org-todo-keyword-faces
'(("ALRT" . (:foreground "Red" :weight bold))
("TODO" . (:foreground "Orange" :weight bold))
("WAIT" . (:foreground "SlateBlue" :weight bold))
("PROG" . (:foreground "DodgerBlue" :weight bold))
("NEXT" . (:foreground "Purple" :weight bold))
("EASY" . (:foreground "MediumSeaGreen" :weight bold))
("DONE" . (:foreground "ForestGreen" :weight bold))))
(setq org-agenda-custom-commands
'(("d" "GTD Dashboard"
;; Begin list of blocks:
(
(tags "+TODO=\"ALRT\""
((org-agenda-overriding-header "🚨 Urgent / Interruptions")))
(tags "+TODO=\"EASY\""
((org-agenda-overriding-header "🍃 Quick Tasks")))
(tags "+TODO=\"PROG\""
((org-agenda-overriding-header "🚧 In Progress")))
(tags "+TODO=\"NEXT\""
((org-agenda-overriding-header "▶ Next Actions")))
(tags "+TODO=\"WAIT\""
((org-agenda-overriding-header "⏳ Pending / Blocked")))
(tags "+TODO=\"TODO\""
((org-agenda-overriding-header "📝 Backlog / To Plan")))
(tags "+TODO=\"DONE\"+CLOSED>=\"<-3d>\""
((org-agenda-overriding-header "✅ Recently Done")))
(agenda ""
((org-agenda-span 1)
(org-agenda-start-day "0d")
(org-agenda-show-all-dates t)
(org-agenda-overriding-header "📅 Todays Schedule")))
(agenda ""
((org-agenda-span 3)
(org-agenda-start-day "+1d")
(org-agenda-overriding-header "📆 Next 3 Days")
(org-agenda-time-grid nil)))
(alltodo ""
((org-agenda-overriding-header "📋 All Tasks")))
) ; End of block-list
) ; End of the "d" command entry
)) ; End of defcustom list
;; Create capture templates
(setq org-capture-templates
`(("t" "Tasks")
("tw" "Work Task" entry (file+headline "~/sync/org/agenda/work.org" "Inbox")
"* TODO %?\n %U\n %i" :empty-lines 1)
("tp" "Personal Task" entry (file+headline "~/sync/org/agenda/personal.org" "Inbox")
"* TODO %?\n %U\n %i" :empty-lines 1)))
;; Tell Org to stop indenting inside of org source blocks.
(setq org-edit-src-content-indentation 0)
;; Set org agenda dir
(setq org-directory "~/sync/org/agenda")
(setq org-agenda-include-diary t)
(setq diary-file "~/sync/org/diary")
(require 'org-tempo)
(dolist (template '(("sh" . "src shell")
("el" . "src emacs-lisp")
("cl" . "src lisp")
("sql" . "src sql")
("py" . "src python")))
(add-to-list 'org-structure-template-alist template))
;; Init org font setup
(opal/org-font-setup))
(use-package org-bullets
:after org
:hook (org-mode . org-bullets-mode)
:custom
(org-bullets-bullet-list '("" "" "" "" "" "" "")))
(defun opal/org-mode-visual-fill ()
(setq visual-fill-column-width 150
visual-fill-column-center-text t)
(visual-fill-column-mode 1))
(use-package visual-fill-column
:hook (org-mode . opal/org-mode-visual-fill))
(use-package! ob
:after org
:config
;; Enable support for these code block languages
(org-babel-do-load-languages
'org-babel-load-languages
'((emacs-lisp . t)
(python . t)
(sql . t)))
;; Support correct font/highlighting for conf-unix blocks
(push '("conf-unix" . conf-unix) org-src-lang-modes))
;; Playing youtube videos via mpv/yt-dlp/emms
(defun opal/play-yt-url-at-point ()
"Play YT link under point with EMMS/MPV/yt-dlp."
(interactive)
(let ((url (thing-at-point 'url t)))
(if url
(emms-play-url url)
(message "No URL found at point."))))
(global-set-key (kbd "C-c y") 'opal/play-yt-url-at-point)
;; Elfeed
(defun opal/elfeed-open-in-eww()
"Open the current Elfeed entry link in eww."
(interactive)
(let ((link (elfeed-entry-link (elfeed-search-selected :single))))
(if link
(eww-browse-url link)
(message "No link to open."))))
(defun opal/elfeed-open-in-firefox()
"Open the current Elfeed entry link in firefox."
(interactive)
(let ((link (elfeed-entry-link (elfeed-search-selected :single))))
(if link
(let ((browse-url-generic-program "firefox"))
(browse-url-generic link))
(message "No link to open."))))
(defun opal/elfeed-mark-all-read ()
"Marks all feeds in *elfeed-search* as read."
(interactive)
(elfeed-untag elfeed-search-entries 'unread)
(elfeed-search-update :force)) ; redraw
(use-package elfeed
:bind
(("C-c e" . elfeed))
:config
;; Ensure faces are set after elfeed has loaded
(set-face-attribute 'elfeed-search-filter-face nil :inherit 'variable-pitch :height 200)
;; Monospace fonts are necessary for text/column alignment in the *elfeed-search* buffer
(set-face-attribute 'elfeed-search-title-face nil :inherit 'fixed-pitch :height 200)
(set-face-attribute 'elfeed-search-feed-face nil :inherit 'fixed-pitch :height 200)
;; Set variable-pitch face for article fonts in the *elfeed-entry* buffer
(add-hook 'elfeed-show-mode-hook
(lambda () (buffer-face-set 'variable-pitch)))
;; Set default search filter
(setq elfeed-search-filter "@2-weeks-ago +unread")
;; Update feeds automatically when entering Elfeed search mode
(add-hook 'elfeed-search-mode-hook 'elfeed-update)
;; Evil keybindings for Elfeed
(evil-define-key 'normal elfeed-search-mode-map
"e" 'opal/elfeed-open-in-eww ;; Open link in eww
"o" 'opal/elfeed-open-in-librewolf ;; Open link in eww
"r" 'opal/elfeed-mark-all-read ;; Marks all feeds as read
"gr" 'elfeed-update ;; Refresh feeds
"q" 'quit-window)) ;; Quit Elfeed
(use-package elfeed-org
:ensure t
:config
(setq rmh-elfeed-org-files '("~/sync/org/elfeed/feeds.org")))
(after! osm
(set-popup-rule! "^\\*osm\\*" :ignore t))
;; eww
;; extra frontends to use:
;; https://eddrit.com
;; https://eu.safereddit.com
;; https://redlib.catsarch.com/
(defun opal/eww-reddit-redirect (url)
"Redirect reddit.com (with or without www) to a privacy frontend."
(replace-regexp-in-string "^https://\\(www\\.\\)?reddit\\.com" "https://old.reddit.com" url))
(defun opal/eww-x-redirect (url)
"Redirect x.com (with or without www) to a privacy frontend."
(replace-regexp-in-string "^https://\\(www\\.\\)?x\\.com" "https://xcancel.com" url))
(defun opal/eww-twitter-redirect (url)
"Redirect twitter.com (with or without www) to a privacy frontend."
(replace-regexp-in-string "^https://\\(www\\.\\)?twitter\\.com" "https://xcancel.com" url))
(global-set-key (kbd "C-c w") #'eww)
(global-set-key (kbd "C-c f") #'elfeed-goodies/show-link-hint)
(defun +opal--eww-fix-fonts-h ()
"Fix fonts, wrapping, and scaling for EWW buffers."
(visual-line-mode 1)
(setq-local face-remapping-alist
'((default variable-pitch default)
(shr-text variable-pitch default)
(shr-link variable-pitch default)
(shr-strong variable-pitch default)
(fixed-pitch fixed-pitch default)
(variable-pitch variable-pitch default)))
(text-scale-set 1))
(use-package! eww
:init
(setq browse-url-browser-function #'eww-browse-url
eww-auto-rename-buffer 'title
reddit-proxy "https://eddrit.com"
eww-url-transformers '(eww-remove-tracking
opal/eww-reddit-redirect
opal/eww-twitter-redirect
opal/eww-x-redirect)
shr-use-fonts nil
shr-fill-text nil)
(after! eww
(set-popup-rule! "^\\*eww" :ignore t))
:hook (eww-mode . +opal--eww-fix-fonts-h))
;; Since I sometimes write notes in two languages, guess-language will allow for multiple language
;; spelling checks to be done in a single buffer.
(use-package guess-language
:defer t
:init (add-hook 'text-mode-hook #'guess-language-mode)
:config
(setq guess-language-langcodes '((en . ("en_US" "English"))
(pt_BR . ("pt_BR" "Brazilian Portuguese")))
guess-language-languages '(en pt_BR)
guess-language-min-paragraph-length 45)
:diminish guess-language-mode)
(defun opal/nov-mode-setup ()
"Configure fonts and layout for nov.el."
(variable-pitch-mode 1)
(visual-line-mode 1)
(setq visual-fill-column-width 150
visual-fill-column-center-text t
line-spacing 0.2)
(visual-fill-column-mode 1))
(use-package! nov
:mode ("\\.epub\\'" . nov-mode)
:hook (nov-mode . opal/nov-mode-setup))
(setq +lookup-dictionary-prefer-offline t)
(setq dictionary-server "dict.org")
(setq browse-url-generic-program "librewolf")
(setq browse-url-browser-function 'browse-url-generic)
(use-package! tramp
:init
;; TRAMP optimizations
;; See: https://coredumped.dev/2025/06/18/making-tramp-go-brrrr
;; Set core TRAMP behavior before it loads
(setq remote-file-name-inhibit-locks t
remote-file-name-inhibit-auto-save-visited t
tramp-use-scp-direct-remote-copying t
tramp-copy-size-limit (* 1024 1024) ;; 1MB
tramp-verbose 2
magit-tramp-pipe-stty-settings 'pty)
:config
;; Enable async remote process copying
(connection-local-set-profile-variables
'remote-direct-async-process
'((tramp-direct-async-process . t)))
(connection-local-set-profiles
'(:application tramp :protocol "scp")
'remote-direct-async-process)
;; Prevent compile mode from disabling SSH ControlMaster
(with-eval-after-load 'compile
(remove-hook 'compilation-mode-hook
#'tramp-compile-disable-ssh-controlmaster-options)))
(use-package emms
:after emms-player-mpd
:config
(require 'emms-setup)
(require 'emms-player-mpd)
(emms-all)
(emms-default-players)
(setq emms-player-list '(emms-player-mpd)
emms-player-mpd-server-name "127.0.0.1"
emms-player-mpd-server-port "6660"
emms-player-mpd-music-directory "~/music")
(add-to-list 'emms-info-functions 'emms-info-mpd)
(emms-player-mpd-connect))