From 6bb6bd1da70858f83f848234cfee8a881881f93d Mon Sep 17 00:00:00 2001 From: Magdalena Szweda Date: Tue, 22 Sep 2026 16:31:35 +0200 Subject: emacs: replace the modular config that takes up a bunch of files with 1 clean config.org file. --- config.el | 523 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 507 insertions(+), 16 deletions(-) (limited to 'config.el') diff --git a/config.el b/config.el index 7eb4158..efb5f57 100644 --- a/config.el +++ b/config.el @@ -1,16 +1,507 @@ -;;; $DOOMDIR/config.el -*- lexical-binding: t; -*- -(load! "+ui") -;; (load! "+dashboard") ; this is the bigger dashboard -(load! "+splash") ; this is the more minimal one -(load! "+maps") -(load! "+colemak") -(load! "+lang") -(load! "+email") -(load! "+jabber") -(load! "+emms") -(load! "+term") -(load! "+git") -(load! "+org") -(load! "+eww") -(load! "+mosey") -(load! "+indent") +(load! "splash") +(defun +splash-initial-buffer () + (splash-screen) + (get-buffer "*splash*")) + +(setq doom-fallback-buffer-name "*splash*" + initial-buffer-choice #'+splash-initial-buffer) + +(defadvice! +splash-regenerate-if-missing-a (&rest _) + :before #'doom-fallback-buffer + (unless (get-buffer "*splash*") + (splash-screen))) + +(add-to-list 'custom-theme-load-path + "~/.config/doom/extra-themes/") +(setq doom-theme 'modus-vivendi) +;; (setq doom-theme 'tango) + +(setq doom-font (font-spec :family "Berkeley Mono" :size 12.0)) + +(setq display-line-numbers-type t) + +(use-package! mood-line + :config + (mood-line-mode) + :custom + (mood-line-glyph-alist mood-line-glyphs-fira-code)) + +(defun my/split-window-dynamically () + "Split the selected window, choosing orientation by its shape." + (interactive) + (select-window + (if (> (window-total-width) (* 2 (window-total-height))) + (split-window-right) + (split-window-below)))) + +(map! :leader "w s" #'my/split-window-dynamically) + +(setq scroll-margin 3) + +(use-package! breadcrumb + :defer t + :hook + (prog-mode . breadcrumb-mode) ;; make sure its in programming modes + :config + (breadcrumb-mode 1)) + +(defun my/hs-eval () + (interactive) + (let* ((src (buffer-file-name)) + (out (file-name-sans-extension src))) + (when (zerop (call-process-shell-command + (format "runghc %s" src) nil "*runghc-output*")) + (let ((buf (make-comint "hs-run" out))) + (display-buffer buf))))) + +(add-hook 'haskell-mode-hook + (lambda () + (local-set-key (kbd "") #'my/hs-eval))) + +(use-package! eglot + :hook + (prog-mode . eglot-ensure)) + +(after! eglot + (cl-defmethod eglot-register-capability + (server (method (eql workspace/didChangeWatchedFiles)) id &key watchers) + nil) + +(add-to-list 'eglot-server-programs + '((typescript-ts-mode javascript-mode) + . ("oxlint" "--lsp")))) + +(setq eglot-sync-connect nil + eglot-connect-timeout 60) + +(after! flycheck + (flycheck-define-checker htmlhint + "htmlhint for flycheck" + :command ("htmlhint" "--format" "unix" source) + :error-patterns + ((error + line-start + (file-name) ":" line ":" column ": " + (message) line-end)) + :modes (web-mode)) + +(add-to-list 'flycheck-checkers 'htmlhint) + +(flycheck-add-next-checker + 'javascript-eslint + 'javascript-oxlint) +(flycheck-add-next-checker + 'html-tidy + 'htmlhint) + +(setq flycheck-check-syntax-automatically + '(save mode-enabled))) + +(use-package! apheleia + :hook (prog-mode . apheleia-mode) + +:config +(setf (alist-get 'oxfmt apheleia-formatters) + '("oxfmt" "--config=.oxfmtrc.json" "--stdin-filepath" filepath)) + +(dolist (mode '(html-mode mhtml-mode web-mode css-mode)) + (setf (alist-get mode apheleia-mode-alist) 'oxfmt))) + +(setq auth-sources '("~/.authinfo.gpg")) + +(setq auth-source-cache-expiry nil) + +(setq gnus-permanently-visible-groups ".") + +(evil-set-initial-state 'gnus-browse-mode 'emacs) + +(setq user-mail-address "hi@roughlynamed.net" ; my email + user-full-name "Magdalena Szweda") ; my name + +(setq mml-secure-openpgp-signers + '("3258B28C124AB0891D6C9E929B72909EEF00CBD0") + mml-secure-openpgp-sign-with-sender t) + +(setq message-signature-file "~/.signature") ; note no trailing slash + +(setq gnus-select-method + '(nnimap "migadu" + (nnimap-address "imap.migadu.com") + (nnimap-server-port 993) + (nnimap-stream ssl))) + +(setq smtpmail-smtp-server "smtp.migadu.com" + smtpmail-smtp-service 465 ; port 465 + smtpmail-stream-type 'ssl + message-send-mail-function #'smtpmail-send-it +) + +(setq gnus-message-archive-method '(nnimap "migadu") ; use migadu for archiving email + gnus-message-archive-group "Sent") ; where to put sent mail + +(setq gnus-large-newsgroup nil + gnus-fetch-old-headers t + nnmail-expiry-target "Trash") + +(add-hook 'message-send-hook #'mml-secure-message-sign-pgpmime) + +(with-eval-after-load "mm-decode" +(add-to-list 'mm-discouraged-alternatives "text/html") +(add-to-list 'mm-discouraged-alternatives "text/richtext")) + +(use-package! jabber + :config + +(setq jabber-account-list + '(("roughlynamed@yax.im"))) + +(jabber-modeline-mode 1) + +:hook +(kill-emacs . jabber-disconnect)) + +(map! :leader + :prefix "j" + :desc "Connect" "c" #'jabber-connect-all + :desc "Disconnect" "q" #'jabber-disconnect + :desc "Dash" "f" #'jabber-roster + :desc "Reply" "r" #'jabber-chat-reply + :desc "New chat" "n" #'jabber-chat-with + :desc "Set status" "s" #'jabber-send-presence) + +(use-package! emms + :commands (emms emms-browser) + +:init +(map! :leader + (:prefix ("e" . "emms") + :desc "Browser" "b" #'emms-browser + :desc "Playlist" "m" #'emms-playlist-mode-go + :desc "Play/pause" "SPC" #'emms-pause + :desc "Next" "n" #'emms-next + :desc "Previous" "p" #'emms-previous + :desc "Stop" "s" #'emms-stop + :desc "Clear" "c" #'emms-playlist-clear)) + +:config +(require 'emms-setup) + +(emms-all) + +(require 'emms-player-mpd) +(setq emms-player-list '(emms-player-mpd) + emms-info-functions '(emms-info-mpd) + +emms-player-mpd-server-name "localhost" +emms-player-mpd-server-port "6600" + +emms-player-mpd-music-directory "~/Music" +emms-source-file-default-directory (expand-file-name "~/Music/") + +emms-repeat-playlist t + +emms-cache-file (concat doom-cache-dir "emms-cache")) + +(add-hook 'emms-playlist-cleared-hook #'emms-player-mpd-clear) + +(emms-player-mpd-connect) + +(emms-mode-line-mode 1) + +(emms-lyrics-toggle-display-on-minibuffer) + +(emms-playing-time-mode 1) + +(map! :map emms-browser-mode-map + :n "RET" #'emms-browser-add-tracks-and-play)) + +(map! + :leader + :prefix "g m" + :desc "Status" "s" #'majutsu ; default majutsu buffer + :desc "Describe" "c" #'majutsu-describe ; equivalent of 'jj describe' + :desc "New" "n" #'majutsu-new ; new jj rev + :desc "Push" "p" #'majutsu-git-push) ; push to git + +(setq org-directory "~/org/") + +(after! org + (setq + org-startup-indented t + org-pretty-entities t + org-hide-emphasis-markers t + org-capture-templates-contexts nil + +org-confirm-babel-evaluate nil) +(org-babel-do-load-languages + 'org-babel-load-languages + '((emacs-lisp . t) + (python . t) + (C . t) + (lisp . t)))) + +(add-hook 'org-capture-mode-hook #'delete-other-windows) +(add-hook 'org-capture-mode-hook + (lambda () (set-window-dedicated-p (selected-window) nil))) + +(after! org-roam + (setq org-roam-directory (file-truename "~/org/")) + +(org-roam-db-autosync-mode) + +(defun my/org-roam-short-id () + (let ((chars "abcdefghijklmnopqrstuvwxyz0123456789")) + (apply #'string + (cl-loop repeat 4 + collect (aref chars (random (length chars))))))) + +(setq org-roam-capture-templates + '(("d" "default" plain + "* %?" + :if-new + +(file+head + (lambda () (concat (my/org-roam-short-id) ".org")) + "#+TITLE: %^{title|Untitled}\n#+FILETAGS: :%^{tags}:\n\n") ; title&tags + :unnarrowed t))) + +(cl-defmethod org-roam-node-file-stem ((node org-roam-node)) + (file-name-base (org-roam-node-file node))) + +(setq org-roam-node-display-template + (concat "${title:*} " (propertize "${file-stem}" 'face 'org-tag))) + +(setq org-roam-mode-sections + '(org-roam-backlinks-section + org-roam-reflinks-section + org-roam-unlinked-references-section)) + +(defun my/org-roam-check-self-link () + (when-let* ((node (org-roam-node-at-point)) + (id (org-roam-node-id node))) + (save-excursion + (goto-char (point-min)) + (while (re-search-forward org-link-any-re nil t) + (when (string-match-p (regexp-quote id) (match-string 0)) + (message "Warning: self-link detected")))))) + +(defun my/org-roam-check-dead-links () + (dolist (link (org-roam-db-query + [:select [dest] :from links + :where (= source $s1)] (org-roam-id-at-point))) + (unless (org-roam-db-query [:select id :from nodes :where (= id $s1)] (car link)) + (message "Error: dead link to %s" (car link))))) + +(add-hook 'before-save-hook + (lambda () + (when (org-roam-file-p) + (my/org-roam-check-self-link) + (my/org-roam-check-dead-links))) + nil t) + +(map! + :leader + :prefix ("n r" . "roam") + :desc "Find node" "f" #'org-roam-node-find ; 'zk edit -i' equivalent + :desc "Insert node" "i" #'org-roam-node-insert ; link a note + :desc "Backlinks" "b" #'org-roam-buffer-toggle + :desc "Capture" "c" #'org-roam-capture ; make a new note + :desc "Graph" "g" #'org-roam-graph ; graph of every note + :desc "Random node" "r" #'org-roam-node-random ; random node + :desc "Open link" "o" #'org-open-at-point ; open linked note under cursor + :desc "Jump back" "O" #'org-mark-ring-goto)) ; jump back to previous note after SPC n r o + +(with-eval-after-load 'ox-html + (setq org-html-xml-declaration nil + org-html-doctype "html5" + org-html-html5-fancy t + +org-html-head-include-default-style nil + +org-html-postamble nil)) + +(use-package! websocket :after org-roam) + +(use-package! org-roam-ui + :after org-roam + :config + (setq org-roam-ui-sync-theme t ; use emacs theme + org-roam-ui-follow t + org-roam-ui-update-on-save t ; update when a org roam file is saved +)) + +(use-package! org-appear + :hook (org-mode . org-appear-mode) + :config + (setq org-appear-autoemphasis t + org-appear-autolinks t + org-appear-autosubmarkers t + org-appear-autoentities t)) + +(setq eww-search-prefix "https://ecosia.org/search?q=") + +(setq eww-download-directory (expand-file-name "~/Downloads/")) + +(defun my-browse-url-mpv (url &rest _args) + "Open URL in mpv." + (start-process "mpv" nil "mpv" url)) + +(defun my-browse-url-pdf (url &rest _args) + "Fetch remote PDF and open in pdf-tools within Emacs." + (let ((tmp (make-temp-file "emacs-pdf-" nil ".pdf"))) + (url-copy-file url tmp t) + (find-file-other-window tmp) + (pdf-view-mode))) + +(defun my/eww-download-image-at-point () + (interactive) + (let ((url (or (get-text-property (point) 'image-url) + (get-text-property (point) 'shr-url)))) + (if (not url) + (message "No image at point") + (let* ((filename (file-name-nondirectory (url-filename (url-generic-parse-url url)))) + (dest (expand-file-name filename eww-download-directory))) + (url-copy-file url dest t) + (message "Saved: %s" dest))))) + +(setq browse-url-handlers + '(("\\(youtube\\.com\\|youtu\\.be\\|vimeo\\.com\\|twitch\\.tv\\)" . my-browse-url-mpv) + ("\\.mp4$" . my-browse-url-mpv) + ("\\.pdf$" . my-browse-url-pdf) + ("^gemini://" . elpher-browse-url-elpher) + ("^gopher://" . elpher-browse-url-elpher) + ("." . eww-browse-url))) + +(setq browse-url-secondary-browser-function 'browse-url-generic + browse-url-generic-program "vivaldi") + +(setq shr-width 100) +(setq shr-max-width 120) +(setq shr-indentation 4) +(setq shr-use-fonts nil) +(setq shr-max-image-size '(800 . 600)) +(setq shr-image-animate t) + +(with-eval-after-load 'eww + (define-key eww-mode-map (kbd "=") #'text-scale-increase) + (define-key eww-mode-map (kbd "-") #'text-scale-decrease) + (define-key eww-mode-map (kbd "0") #'text-scale-adjust) + (define-key eww-mode-map (kbd "b") #'eww-back-url) + (define-key eww-mode-map (kbd "a") #'eww-add-bookmark) + (define-key eww-mode-map (kbd "U") #'shr-copy-url) + (define-key eww-mode-map (kbd "D") #'my/eww-download-image-at-point) + (evil-define-key 'normal eww-mode-map + "b" #'eww-back-url + "a" #'eww-add-bookmark + "U" #'shr-copy-url + "D" #'my/eww-download-image-at-point)) + +(provide 'browser) + +(use-package! mosey + :commands (mosey-forward mosey-backward + mosey-forward-bounce mosey-backward-bounce + mosey-forward-cycle mosey-backward-cycle)) + +(map! :leader + (:prefix ("k" . "mosey") + :desc "Mosey backward" "a" #'mosey-backward-bounce + :desc "Mosey forward" "e" #'mosey-forward-bounce)) + +(use-package! aggressive-indent + :config + (global-aggressive-indent-mode 1)) ; use aggressive-indent everywhere + +(map! + :leader + :prefix "o" + :desc "Woman" "w" #'helm-man-woman) + +(map! + :leader + :prefix "d" + :desc "Dired" "d" #'dired + :desc "Dired here" "h" #'dired-jump) + +(remove-hook 'doom-first-input-hook #'evil-snipe-mode) + +(after! evil-org + (evil-define-key 'normal evil-org-mode-map + "o" #'evil-forward-char)) + +(evil-define-key '(normal visual operator) 'global + "n" 'evil-backward-char + "e" 'evil-next-line + "i" 'evil-previous-line + "o" 'evil-forward-char) + +(evil-define-key '(normal visual operator) 'global + "l" 'evil-backward-word-begin + "L" 'evil-backward-WORD-begin + "u" 'evil-forward-word-end + "U" 'evil-forward-WORD-end + "y" 'evil-forward-word-begin + "Y" 'evil-forward-word-begin) + +(with-eval-after-load 'evil-ex + (define-key evil-ex-completion-map (kbd "C-l") 'left-word) + (define-key evil-ex-completion-map (kbd "C-y") 'right-word)) + +(evil-define-key 'normal 'global + "s" 'evil-insert + "S" 'evil-insert-line + "t" 'evil-append + "T" 'evil-append-line + "h" 'evil-open-below + "H" 'evil-open-above) + +(evil-define-key '(normal visual) 'global + "w" 'evil-change + "W" 'evil-change-line) + +(evil-define-key 'normal 'global + "x" 'evil-delete-char + "c" 'evil-yank + "v" 'evil-paste-after + "X" 'evil-delete-line + "C" 'evil-yank-line + "V" 'evil-paste-before) + +(evil-define-key 'visual 'global + "x" 'evil-delete + "c" 'evil-yank + "v" 'evil-paste-after) + +(evil-define-key 'normal 'global + "z" 'evil-undo + "Z" 'evil-redo) + +(evil-define-key 'normal 'global + "a" 'evil-visual-char + "A" 'evil-visual-line + "ga" 'evil-visual-restore) + +(evil-define-key '(normal visual operator) 'global + "p" 'evil-find-char-to + "P" 'evil-find-char-to-backward + "b" 'evil-repeat-find-char + "B" 'evil-repeat-find-char-reverse + "k" 'evil-search-next + "K" 'evil-search-previous) + +(with-eval-after-load 'evil + (evil-define-key '(operator visual) 'global "r" evil-inner-text-objects-map)) + +(define-prefix-command 'my-colemak-fold-map) +(evil-define-key '(normal visual) 'global "j" 'my-colemak-fold-map) +(define-key my-colemak-fold-map "j" 'evil-scroll-line-to-center) +(define-key my-colemak-fold-map "n" 'evil-scroll-line-to-top) +(define-key my-colemak-fold-map "e" 'evil-scroll-line-to-bottom) + +(evil-define-key 'normal 'global + "gK" 'evil-lookup) + +(map! :n "SPC w n" #'evil-window-left + :n "SPC w e" #'evil-window-down + :n "SPC w i" #'evil-window-up + :n "SPC w o" #'evil-window-right) -- cgit v1.2.3