From be7e6871ed9d71d217ef144b5c5b6c5be5f9f5bd 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. --- doom/.config/doom/+colemak.el | 84 ---- doom/.config/doom/+dashboard.el | 30 -- doom/.config/doom/+eglot.el | 18 - doom/.config/doom/+email.el | 37 -- doom/.config/doom/+emms.el | 33 -- doom/.config/doom/+eww.el | 66 --- doom/.config/doom/+flycheck.el | 21 - doom/.config/doom/+format.el | 10 - doom/.config/doom/+git.el | 8 - doom/.config/doom/+indent.el | 4 - doom/.config/doom/+jabber.el | 17 - doom/.config/doom/+lang.el | 17 - doom/.config/doom/+maps.el | 10 - doom/.config/doom/+mosey.el | 10 - doom/.config/doom/+org.el | 104 ----- doom/.config/doom/+splash.el | 58 --- doom/.config/doom/+term.el | 3 - doom/.config/doom/+ui.el | 41 -- doom/.config/doom/config.el | 523 ++++++++++++++++++++- doom/.config/doom/config.org | 972 ++++++++++++++++++++++++++++++++++++++++ doom/.config/doom/init.el | 4 +- doom/.config/doom/splash.el | 57 +++ 22 files changed, 1538 insertions(+), 589 deletions(-) delete mode 100644 doom/.config/doom/+colemak.el delete mode 100644 doom/.config/doom/+dashboard.el delete mode 100644 doom/.config/doom/+eglot.el delete mode 100644 doom/.config/doom/+email.el delete mode 100644 doom/.config/doom/+emms.el delete mode 100644 doom/.config/doom/+eww.el delete mode 100644 doom/.config/doom/+flycheck.el delete mode 100644 doom/.config/doom/+format.el delete mode 100644 doom/.config/doom/+git.el delete mode 100644 doom/.config/doom/+indent.el delete mode 100644 doom/.config/doom/+jabber.el delete mode 100644 doom/.config/doom/+lang.el delete mode 100644 doom/.config/doom/+maps.el delete mode 100644 doom/.config/doom/+mosey.el delete mode 100644 doom/.config/doom/+org.el delete mode 100644 doom/.config/doom/+splash.el delete mode 100644 doom/.config/doom/+term.el delete mode 100644 doom/.config/doom/+ui.el create mode 100644 doom/.config/doom/config.org create mode 100644 doom/.config/doom/splash.el diff --git a/doom/.config/doom/+colemak.el b/doom/.config/doom/+colemak.el deleted file mode 100644 index 132fa8b..0000000 --- a/doom/.config/doom/+colemak.el +++ /dev/null @@ -1,84 +0,0 @@ -;;; $DOOMDIR/+colemak.el -*- lexical-binding: t; -*- - -(remove-hook 'doom-first-input-hook #'evil-snipe-mode) -(evil-set-initial-state 'gnus-browse-mode 'emacs) -(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) diff --git a/doom/.config/doom/+dashboard.el b/doom/.config/doom/+dashboard.el deleted file mode 100644 index a751684..0000000 --- a/doom/.config/doom/+dashboard.el +++ /dev/null @@ -1,30 +0,0 @@ -;;; $DOOMDIR/+dashboard.el -*- lexical-binding: t; -*- - -(defvar dashboard-messages - '("Vi-Vi-Vi editor of the beast" - "Welcome to Emacs" - "M-x M-x" - "nnngh *humps* get pregnant!!!" - "tetris, a therapist, web browser, music player... oh and a text editor if youre into that." - "wranglin' emacs" - "wranglin' gnu" - "teco? i hardly know 'er" - "teco? thats a bad joke" - "you can do that in emacs" - "pig destroyer" - "billions will abudabi" - "billions will die" - "evil is cringe - dustmite" - "free as in freedom" - "i extract carbon packets out of sun foam")) -(defun my/dashboard-random-message () - (nth (random (length dashboard-messages)) - dashboard-messages)) -(use-package! minimal-dashboard - :init - (setq initial-buffer-choice #'minimal-dashboard) - :custom - (minimal-dashboard-buffer-name "*dash*") - (minimal-dashboard-text #'my/dashboard-random-message) - (minimal-dashboard-modeline-shown 1)) -(setq doom-fallback-buffer-name "*dash*") diff --git a/doom/.config/doom/+eglot.el b/doom/.config/doom/+eglot.el deleted file mode 100644 index 2f26d72..0000000 --- a/doom/.config/doom/+eglot.el +++ /dev/null @@ -1,18 +0,0 @@ -;;; $DOOMDIR/+eglot.el -*- lexical-binding: t; -*- -;; TODO: make eglot work with HTML -(use-package! eglot - :hook - (prog-mode . eglot-ensure) - (markdown-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 - '((markdown-mode) - . ("zk" "lsp"))) - (add-to-list 'eglot-server-programs - '((typescript-ts-mode javascript-mode) - . ("oxlint" "--lsp")))) -(setq eglot-sync-connect nil - eglot-connect-timeout 60) diff --git a/doom/.config/doom/+email.el b/doom/.config/doom/+email.el deleted file mode 100644 index df06bea..0000000 --- a/doom/.config/doom/+email.el +++ /dev/null @@ -1,37 +0,0 @@ -;;; $DOOMDIR/+email.el -*- lexical-binding: t; -*- -(setq auth-sources '("~/.authinfo.gpg") - auth-source-cache-expiry nil) -(setq gnus-permanently-visible-groups ".") -(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 - smtpmail-stream-type 'ssl - message-send-mail-function #'smtpmail-send-it) - -(setq user-mail-address "hi@roughlynamed.net" - user-full-name "Magdalena Szweda") - -(setq gnus-message-archive-method '(nnimap "migadu") - gnus-message-archive-group "Sent") - -(setq gnus-large-newsgroup nil - gnus-fetch-old-headers t - nnmail-expiry-target "Trash") - -(setq mml-secure-openpgp-signers - '("3258B28C124AB0891D6C9E929B72909EEF00CBD0") - mml-secure-openpgp-sign-with-sender t) - -(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")) -(setq message-signature-file "~/.signature") -(map! :map message-mode-map - :localleader - "s" #'message-send-and-exit - "S" #'message-send) diff --git a/doom/.config/doom/+emms.el b/doom/.config/doom/+emms.el deleted file mode 100644 index 3b03e9e..0000000 --- a/doom/.config/doom/+emms.el +++ /dev/null @@ -1,33 +0,0 @@ -;;; $DOOMDIR/+emms.el -*- lexical-binding: t; -*- -(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-lyrics-toggle-display-on-modeline) - (emms-playing-time-mode 1) - (map! :map emms-browser-mode-map - :n "RET" #'emms-browser-add-tracks-and-play)) diff --git a/doom/.config/doom/+eww.el b/doom/.config/doom/+eww.el deleted file mode 100644 index 7f8c97c..0000000 --- a/doom/.config/doom/+eww.el +++ /dev/null @@ -1,66 +0,0 @@ -;;; $DOOMDIR/+eww.el -*- lexical-binding: 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))) - -(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))) - -;; Keep your fallback setting -(setq browse-url-secondary-browser-function 'browse-url-generic - browse-url-generic-program "chromium") - -(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)) - -(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) - -(defun my/eww-download-image-at-point () - "Download image at point to `eww-download-directory'." - (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))))) - -;; Keybinds -(with-eval-after-load 'eww - (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) diff --git a/doom/.config/doom/+flycheck.el b/doom/.config/doom/+flycheck.el deleted file mode 100644 index 0b184b3..0000000 --- a/doom/.config/doom/+flycheck.el +++ /dev/null @@ -1,21 +0,0 @@ -;;; $DOOMDIR/+flycheck.el -*- lexical-binding: t; -*- -;; TODO: fix linter not working (not popping up and stuff) -(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))) diff --git a/doom/.config/doom/+format.el b/doom/.config/doom/+format.el deleted file mode 100644 index c5bbc79..0000000 --- a/doom/.config/doom/+format.el +++ /dev/null @@ -1,10 +0,0 @@ -;;; $DOOMDIR/+format.el -*- lexical-binding: t; -*- -(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))) - diff --git a/doom/.config/doom/+git.el b/doom/.config/doom/+git.el deleted file mode 100644 index 09790f0..0000000 --- a/doom/.config/doom/+git.el +++ /dev/null @@ -1,8 +0,0 @@ -;;; $DOOMDIR/+git.el -*- lexical-binding: t; -*- -(map! - :leader - :prefix "g m" - :desc "Status" "s" #'majutsu - :desc "Describe" "c" #'majutsu-describe - :desc "New" "n" #'majutsu-new - :desc "Push" "p" #'majutsu-git-push) diff --git a/doom/.config/doom/+indent.el b/doom/.config/doom/+indent.el deleted file mode 100644 index 4f55797..0000000 --- a/doom/.config/doom/+indent.el +++ /dev/null @@ -1,4 +0,0 @@ -;;; $DOOMDIR/+indent.el -*- lexical-binding: t; -*- -(use-package! aggressive-indent - :config - (global-aggressive-indent-mode 1)) diff --git a/doom/.config/doom/+jabber.el b/doom/.config/doom/+jabber.el deleted file mode 100644 index 23b420f..0000000 --- a/doom/.config/doom/+jabber.el +++ /dev/null @@ -1,17 +0,0 @@ -;;; $DOOMDIR/+jabber.el -*- lexical-binding: t; -*- -(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) diff --git a/doom/.config/doom/+lang.el b/doom/.config/doom/+lang.el deleted file mode 100644 index 6ae23c5..0000000 --- a/doom/.config/doom/+lang.el +++ /dev/null @@ -1,17 +0,0 @@ -;;; $DOOMDIR/+lang.el -*- lexical-binding: t; -*- -(load! "+eglot") -(load! "+flycheck") -(load! "+format") - -;; functions -(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))) diff --git a/doom/.config/doom/+maps.el b/doom/.config/doom/+maps.el deleted file mode 100644 index 2be1d51..0000000 --- a/doom/.config/doom/+maps.el +++ /dev/null @@ -1,10 +0,0 @@ -;;; $DOOMDIR/+maps.el -*- lexical-binding: t; -*- -(map! - :leader - :prefix "o" - :desc "Woman" "w" #'helm-man-woman) -(map! - :leader - :prefix "d" - :desc "Dired" "d" #'dired - :desc "Dired here" "h" #'dired-jump) diff --git a/doom/.config/doom/+mosey.el b/doom/.config/doom/+mosey.el deleted file mode 100644 index 06b7c33..0000000 --- a/doom/.config/doom/+mosey.el +++ /dev/null @@ -1,10 +0,0 @@ -;;; $DOOMDIR/+mosey.el -*- lexical-binding: t; -*- - -(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)) diff --git a/doom/.config/doom/+org.el b/doom/.config/doom/+org.el deleted file mode 100644 index fbd57db..0000000 --- a/doom/.config/doom/+org.el +++ /dev/null @@ -1,104 +0,0 @@ -;;; $DOOMDIR/+org.el -*- lexical-binding: t; -*- -(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") - :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 - :desc "Insert node" "i" #'org-roam-node-insert - :desc "Backlinks" "b" #'org-roam-buffer-toggle - :desc "Capture" "c" #'org-roam-capture - :desc "Graph" "g" #'org-roam-graph - :desc "Random node" "r" #'org-roam-node-random - :desc "Toggle buffer" "t" #'org-roam-buffer-toggle - :desc "Open link" "o" #'org-open-at-point - :desc "Jump back" "O" #'org-mark-ring-goto)) -(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 - org-roam-ui-follow t - org-roam-ui-update-on-save t)) -(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)) diff --git a/doom/.config/doom/+splash.el b/doom/.config/doom/+splash.el deleted file mode 100644 index e76098e..0000000 --- a/doom/.config/doom/+splash.el +++ /dev/null @@ -1,58 +0,0 @@ -;;; $DOOMDIR/+splash.el -*- lexical-binding: t; -*- - -;;; Code: - -(defun splash--center (str width) - "Return STR centered in WIDTH columns." - (let ((pad (max 0 (/ (- width (string-width str)) 2)))) - (concat (make-string pad ?\s) str))) - -(defun splash-screen () - "Show the splash screen." - (interactive) - (let ((buf (get-buffer-create "*splash*"))) - (with-current-buffer buf - (let ((inhibit-read-only t)) - (erase-buffer) - (when (one-window-p) - (setq mode-line-format nil)) - (setq cursor-type nil) - (let* ((height (- (window-body-height nil) 1)) - (width (window-body-width nil)) - (pad-top (- (/ height 2) 1)) - (pad-bottom (- height (/ height 2) 3)) - (emacs-str (format "GNU Emacs version %d.%d" - emacs-major-version - emacs-minor-version))) - (insert (make-string pad-top ?\n)) - (insert (splash--center "www.gnu.org" width) "\n") - (insert (splash--center emacs-str width) "\n") - (insert (splash--center "A free/libre editor" width) "\n") - (insert (make-string pad-bottom ?\n)) - (insert (splash--center "GNU Emacs comes with ABSOLUTELY NO WARRANTY" width) "\n") - (insert (splash--center "Copyright (C) 2026 Free Software Foundation, Inc." width) "\n")) - (goto-char (point-min)) - (read-only-mode 1) - (use-local-map (make-sparse-keymap)))))) - -(defun splash-screen-kill () - "Kill the splash buffer." - (interactive) - (when (get-buffer "*splash*") - (kill-buffer "*splash*"))) - -(if (daemonp) - (add-hook 'server-after-make-frame-hook - (lambda () - (run-with-timer 0.15 nil #'splash-screen))) - (when (and (not (member "-no-splash" command-line-args)) - (not (member "--file" command-line-args)) - (not (member "--insert" command-line-args)) - (not (member "--find-file" command-line-args))) - (add-hook 'window-setup-hook #'splash-screen) - (setq inhibit-startup-screen t - inhibit-startup-message t - inhibit-startup-echo-area-message t))) - -(provide 'splash-screen) -;;; splash.el ends here diff --git a/doom/.config/doom/+term.el b/doom/.config/doom/+term.el deleted file mode 100644 index 1d8f2b9..0000000 --- a/doom/.config/doom/+term.el +++ /dev/null @@ -1,3 +0,0 @@ -;;; $DOOMDIR/+term.el -*- lexical-binding: t; -*- -(setq-default vterm-shell "/usr/bin/fish") -(setq-default explicit-shell-file-name "/usr/bin/fish") diff --git a/doom/.config/doom/+ui.el b/doom/.config/doom/+ui.el deleted file mode 100644 index eed34e9..0000000 --- a/doom/.config/doom/+ui.el +++ /dev/null @@ -1,41 +0,0 @@ -;;; $DOOMDIR/+ui.el -*- lexical-binding: t; -*- -(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-font (font-spec :family "Berkeley Mono" :size 12.0)) -(setq doom-theme 'modus-vivendi) -;; (setq doom-theme 'tango) -(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) - :config - (breadcrumb-mode 1)) diff --git a/doom/.config/doom/config.el b/doom/.config/doom/config.el index 7eb4158..efb5f57 100644 --- a/doom/.config/doom/config.el +++ b/doom/.config/doom/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) diff --git a/doom/.config/doom/config.org b/doom/.config/doom/config.org new file mode 100644 index 0000000..9a87eaa --- /dev/null +++ b/doom/.config/doom/config.org @@ -0,0 +1,972 @@ +#+TITLE: Doom Emacs configuration +#+PROPERTY: header-args:emacs-lisp :tangle config.el +Hello! This is my literate configuration for Doom Emacs. +Why literate? because org is cool! +Made with org-babel (the little begin_src blocks) + +* Splash screen +This is my custom splash screen for Emacs. +#+begin_src emacs-lisp +(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))) +#+end_src +The splash screen doesnt do much, it prints the emacs version and a warranty notice and whatnot. i like it tho! + +* UI +~How Emacs looks!~ +** Theme +Load the directory with additional, local themes +This currently mostly loads the emacs port of the Evergarden theme (made by me!) +at [[https://codeberg.org/roughlynamed/emacs-evergarden][roughlynamed/emacs-evergarden]], also the fortune-gold theme. +The reason i use modus-vivendi instead of my evergarden port is because i dont like evergarden (dont tell the devs though!), seeing it not have an emacs port just made me sad. +I also use tango from time-to-time, thats the comment. +#+begin_src emacs-lisp +(add-to-list 'custom-theme-load-path + "~/.config/doom/extra-themes/") +(setq doom-theme 'modus-vivendi) +;; (setq doom-theme 'tango) +#+end_src +** Font +I use the completely not pirated ~Berkeley Mono~ font. I really like it. +Sometimes i will use the Commit mono font (sometimes!) +#+begin_src emacs-lisp +(setq doom-font (font-spec :family "Berkeley Mono" :size 12.0)) +#+end_src + +Line numbers! And not relative! +I dont like rln, i just dont +#+begin_src emacs-lisp +(setq display-line-numbers-type t) +#+end_src +** Modeline +The emacs mood line, It's nice and simple which i adore. +I might have to try out the default modeline from Emacs sometime though. +#+begin_src emacs-lisp +(use-package! mood-line + :config + (mood-line-mode) + :custom + (mood-line-glyph-alist mood-line-glyphs-fira-code)) +#+end_src + +** Custom window management +I didnt like how in emacs, split windows under ~SPC w s~ just stack, so i made this function to make it dynamic in a fibonnaci-like layout. +#+begin_src emacs-lisp +(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)))) +#+end_src + +Map the function to override ~SPC w s~ +#+begin_src emacs-lisp +(map! :leader "w s" #'my/split-window-dynamically) +#+end_src + +** UX ~ UI +Scroll margin - when the cursor reaches 3 lines above/below the window bottom/top, the window goes down (this happens in helix automatically, but the margin is 5) +#+begin_src emacs-lisp +(setq scroll-margin 3) +#+end_src + +** Breadcrumb +Breadcrumb is a package that shows you where you are in a file at the very top of the window. Editing this section of this file, the breadcrumb shows: +~stow/d/.config/doom/config.org : UI~, +this is because we are in the UI section of the file. +#+begin_src emacs-lisp +(use-package! breadcrumb + :defer t + :hook + (prog-mode . breadcrumb-mode) ;; make sure its in programming modes + :config + (breadcrumb-mode 1)) +#+end_src + +* Languages & LSP +~M-x vscode~ +** Haskell +A custom function that runs the current Haskell file with runghc (interpreter instead of a compiler). +#+begin_src emacs-lisp +(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))))) +#+end_src + +** TODO make this a ~SPC~-based binding +Hook the function up up to f5 +#+begin_src emacs-lisp +(add-hook 'haskell-mode-hook + (lambda () + (local-set-key (kbd "") #'my/hs-eval))) +#+end_src + +** Eglot +Eglot is, well, LSP for Emacs! +Here i hook eglot-ensure into prog-mode. +eglot-ensure makes sure that eglot is enabled and working when opening a prog-mode buffer now. +#+begin_src emacs-lisp +(use-package! eglot + :hook + (prog-mode . eglot-ensure)) +#+end_src + +I copied this block from somewhere and have no idea what it does. +#+begin_src emacs-lisp +(after! eglot + (cl-defmethod eglot-register-capability + (server (method (eql workspace/didChangeWatchedFiles)) id &key watchers) + nil) +#+end_src + + +Here we add a custom LSP for typescript and javascript mode. +Oxlint is a rewrite of ESLint in Rust, Not sure why oxlsp isnt its own tool, but oh well. +#+begin_src emacs-lisp + (add-to-list 'eglot-server-programs + '((typescript-ts-mode javascript-mode) + . ("oxlint" "--lsp")))) +#+end_src + +~eglot-sync-connect~ makes it so that eglot has to catch up and connect before a buffer can be worked on, thats why i set it to nil. +~eglot-connect-timeout~ just stops trying to connect to eglot after a minute. +#+begin_src emacs-lisp +(setq eglot-sync-connect nil + eglot-connect-timeout 60) +#+end_src + +** Flycheck +Flycheck is a linter engine for Emacs. + +Here i define a new checker for flycheck, htmlhint (which is the linter i most enjoy using). +Then i hook it into ~web-mode~ +#+begin_src emacs-lisp +(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)) +#+end_src + +I then add the new checker to the flycheck checkers (say that 3 times fast) +#+begin_src emacs-lisp +(add-to-list 'flycheck-checkers 'htmlhint) +#+end_src + +Here we add additional checkers to flycheck. +We add ESLint and oxlint, and then another block for html-tidy and the new htmlhint. +The reason this cant be all in one ~flycheck-add-next-checker~ block is because ~flyckech-add-next-checker~ only takes 2 variables. +#+begin_src emacs-lisp + (flycheck-add-next-checker + 'javascript-eslint + 'javascript-oxlint) + (flycheck-add-next-checker + 'html-tidy + 'htmlhint) +#+end_src + +We then make flycheck check the file after saving. +#+begin_src emacs-lisp + (setq flycheck-check-syntax-automatically + '(save mode-enabled))) +#+end_src + +** Apheleia + +Apheleia is an easy way to format your files in Emacs. +First we hook apheleia into prog-mode. +#+begin_src emacs-lisp +(use-package! apheleia + :hook (prog-mode . apheleia-mode) +#+end_src + +We can then add a new apheleia formatter, in this case oxfmt. +(why is oxfmt its own tool but oxlsp isnt? why cant it just be ~oxlint --lsp~ and ~oxlint --format~, this is dumb) +#+begin_src emacs-lisp + :config + (setf (alist-get 'oxfmt apheleia-formatters) + '("oxfmt" "--config=.oxfmtrc.json" "--stdin-filepath" filepath)) +#+end_src + +Here we hook the new oxfmt formatter into: ++ html-mode ++ mhtml-mode ++ web-mode ++ css-mode +#+begin_src emacs-lisp + (dolist (mode '(html-mode mhtml-mode web-mode css-mode)) + (setf (alist-get mode apheleia-mode-alist) 'oxfmt))) +#+end_src + +* Email +~Emacs - prover of Zawinki's law~ +** Auth +To send mail, we need to log into everything. +Instead of typing out passwords every time, we use the ~~.authinfo.gpg~ file (can also be without the gpg encryption). +To read the file: +#+begin_src emacs-lisp +(setq auth-sources '("~/.authinfo.gpg")) +#+end_src +Emacs automatically decrypts the file with ~epa~ and ~epg~. +To make this not expire, we set +#+begin_src emacs-lisp +(setq auth-source-cache-expiry nil) +#+end_src + +** Gnus +Gnus is Emacs's built in Email reader, sender, news viewer and RSS reader. +But right now we're setting up the Email part. + +This makes it so that all subscribed groups are visible, no matter if theres no new messages. + +#+begin_src emacs-lisp +(setq gnus-permanently-visible-groups ".") +#+end_src + +When browsing gnus, make the mode in evil standard emacs. +#+begin_src emacs-lisp +(evil-set-initial-state 'gnus-browse-mode 'emacs) +#+end_src +Now we configure our user of gnus. +#+begin_src emacs-lisp +(setq user-mail-address "hi@roughlynamed.net" ; my email + user-full-name "Magdalena Szweda") ; my name +#+end_src +While we're at it, lets point Emacs at my LibrePGP key. +#+begin_src emacs-lisp +(setq mml-secure-openpgp-signers + '("3258B28C124AB0891D6C9E929B72909EEF00CBD0") + mml-secure-openpgp-sign-with-sender t) +#+end_src +We can also set up the signature via the ~.signature~ file instead of encoding it raw into the config. +#+begin_src emacs-lisp +(setq message-signature-file "~/.signature") ; note no trailing slash +#+end_src + +Now we can set up the actual mail part. +I use migadu for my email hosting, provided to me by ~@bas.sh~ +Here we set up IMAP for receiving mail. +#+begin_src emacs-lisp +(setq gnus-select-method + '(nnimap "migadu" + (nnimap-address "imap.migadu.com") + (nnimap-server-port 993) + (nnimap-stream ssl))) +#+end_src +Once that's done, we can configure the sending (smtp) part. +#+begin_src emacs-lisp +(setq smtpmail-smtp-server "smtp.migadu.com" + smtpmail-smtp-service 465 ; port 465 + smtpmail-stream-type 'ssl + message-send-mail-function #'smtpmail-send-it +) +#+end_src + +After that, a little bit more config for UX +#+begin_src emacs-lisp +(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") +#+end_src + +I like to sign my message with pgp as a way to confirm that its really me sending the email. +We can do this with the following: +#+begin_src emacs-lisp +(add-hook 'message-send-hook #'mml-secure-message-sign-pgpmime) +#+end_src +We use pgpmime to put the signature in the MIME header instead of inline PGP blocks. + +I'm not a fan of html in my emails as i find it rendering bad and being hard to navigate, so i set it to discourage html and prefer plain text emails. +#+begin_src emacs-lisp +(with-eval-after-load "mm-decode" +(add-to-list 'mm-discouraged-alternatives "text/html") +(add-to-list 'mm-discouraged-alternatives "text/richtext")) +#+end_src + +* Jabber +~Jabber? I hardly know her!~ + +Excuse the bad pun, jabber.el is a way to use XMPP in Emacs. +#+begin_src emacs-lisp +(use-package! jabber + :config +#+end_src +We point jabber at my XMPP account: +#+begin_src emacs-lisp +(setq jabber-account-list + '(("roughlynamed@yax.im"))) +#+end_src +And let jabber use the modeline +#+begin_src emacs-lisp +(jabber-modeline-mode 1) +#+end_src +Now, we can hook jabber to kill itself when emacs dies. +#+begin_src emacs-lisp +:hook +(kill-emacs . jabber-disconnect)) +#+end_src +As to not rely on ~M-x~ commands, define a binding as so +#+begin_src emacs-lisp +(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) +#+end_src + + +* EMMS +~Music to my ears~ +EMMS, the Emacs MultiMedia System (but mostly its just used for music). + +Declare the package block and set up the commands. +** TODO put the following prose in an org-roam file +~:commands~ in elisp is used to eagerly load functions even when a package is lazy loaded. +The following makes the commands ~emms~ and ~emms-browser~ available even before emms itself is loaded. +#+begin_src emacs-lisp +(use-package! emms + :commands (emms emms-browser) +#+end_src + +Configure the mappings for EMMS +** TODO put the following prose in an org-roam file +~:init~ in elisp runs the following code =before= a package is loaded. +In this case, it makes the emms mappings available right when emacs starts up. +#+begin_src emacs-lisp + :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)) +#+end_src + +Here we tell EMMS to use the preset configuration loader, this makes it so that i dont have to wire up a bunch of emms submodules myself. +#+begin_src emacs-lisp + :config + (require 'emms-setup) +#+end_src + +We then use ~emms-all~ to load every emms submodule. Possible variations include: +| Name | What it does | +|----------------+----------------------------------------------------------------| +| ~emms-all~ | Loads every EMMS submodule. (browser, cover art, lyrics, etc.) | +|----------------+----------------------------------------------------------------| +| ~emms-standard~ | Smaller and more curated subset of features | +|----------------+----------------------------------------------------------------| +| ~emms-minimal~ | Very barebones EMMS | + +#+begin_src emacs-lisp + (emms-all) +#+end_src + +Here we tell EMMS to use MPD instead of MPRIS. +#+begin_src emacs-lisp + (require 'emms-player-mpd) + (setq emms-player-list '(emms-player-mpd) + emms-info-functions '(emms-info-mpd) +#+end_src + + +Here we point EMMS/MPD at the default server and port for MPD +#+begin_src emacs-lisp +emms-player-mpd-server-name "localhost" +emms-player-mpd-server-port "6600" +#+end_src + +Tell EMMS where MPD's music dir lives, and where its own music dir lives. +#+begin_src emacs-lisp +emms-player-mpd-music-directory "~/Music" +emms-source-file-default-directory (expand-file-name "~/Music/") +#+end_src + +Make playlists loop instead of stopping at the last track. +#+begin_src emacs-lisp +emms-repeat-playlist t +#+end_src + +Make EMMS use Doom Emacs' cache instead of its own. +#+begin_src emacs-lisp +emms-cache-file (concat doom-cache-dir "emms-cache")) +#+end_src + +Clear the playlist both on EMMS and MPD +#+begin_src emacs-lisp +(add-hook 'emms-playlist-cleared-hook #'emms-player-mpd-clear) +#+end_src + +Connect to MPD as soon as this config loads. +#+begin_src emacs-lisp +(emms-player-mpd-connect) +#+end_src + +Turn on the little [ARTIST - ALBUM - TITLE] indicator in the modeline. +#+begin_src emacs-lisp +(emms-mode-line-mode 1) +#+end_src + +Show lyrics in the buffer whenever its free +#+begin_src emacs-lisp +(emms-lyrics-toggle-display-on-minibuffer) +#+end_src + +LISTENED/LENGTH indicator in the modeline +#+begin_src emacs-lisp +(emms-playing-time-mode 1) +#+end_src + +This makes it so that presing RET on a song in normal mode adds the tracks to the playlist and plays it. +This currently doesnt work. +#+begin_src emacs-lisp +(map! :map emms-browser-mode-map + :n "RET" #'emms-browser-add-tracks-and-play)) +#+end_src + + + +* Git +~LEAVE Emacs? You gotta be kidding.~ +** Majutsu +I use the JuJutsu version control system. +I am an old user of ~magit~. Why not use magit for JJ? + +Define mappings for the already-installed ~majutsu~ +Open the main majutsu buffer. +#+begin_src emacs-lisp +(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 +#+end_src + +* Org +~Protesting for Org README support.~ +Org is Emacs's version of markdown, and is what this file is written in. + +Tell org what directory to use +#+begin_src emacs-lisp +(setq org-directory "~/org/") +#+end_src + +Now it's time to get to the guts; the main org config. +But first, some good 'ol self-documenting code: +#+begin_src emacs-lisp +(after! org + (setq + org-startup-indented t + org-pretty-entities t + org-hide-emphasis-markers t + org-capture-templates-contexts nil +#+end_src +** Org Babel +Org babel is Org's version of code blocks. +Every code block defined above and below is made via org-babel and the following config. +#+begin_src emacs-lisp + org-confirm-babel-evaluate nil) + (org-babel-do-load-languages + 'org-babel-load-languages + '((emacs-lisp . t) + (python . t) + (C . t) + (lisp . t)))) +#+end_src + +** Org UX +This makes org capturing much better. +When capturing a new org note, all windows are deleted, and the capture window is made a dedicated window. +#+begin_src emacs-lisp +(add-hook 'org-capture-mode-hook #'delete-other-windows) +(add-hook 'org-capture-mode-hook + (lambda () (set-window-dedicated-p (selected-window) nil))) +#+end_src + +** TODO Org roam +As much as i'd love to put it under its own higher header, that would be nonsensical. +Org roam is org's way of a Zettelkasten style knowledge place. Something like obsidian, logseq or ~zk~. Another plus is everything lives in a ~SQLite~ database. + +Point org-roam at the org directory (declared seperately). +#+begin_src emacs-lisp +(after! org-roam + (setq org-roam-directory (file-truename "~/org/")) +#+end_src + +Make roam sync it's database automatically. +#+begin_src emacs-lisp + (org-roam-db-autosync-mode) +#+end_src + +This is a custom function, i made it to mimic how the ~zk~ cli works when making a new note, which is usually a random 4 character string. for example ~zqy2.md~ could be a note. +#+begin_src emacs-lisp + (defun my/org-roam-short-id () + (let ((chars "abcdefghijklmnopqrstuvwxyz0123456789")) + (apply #'string + (cl-loop repeat 4 + collect (aref chars (random (length chars))))))) + + +#+end_src + +The template for new org notes. +#+begin_src emacs-lisp +(setq org-roam-capture-templates + '(("d" "default" plain + "* %?" + :if-new +#+end_src + +Here we use the function defined above to name the captured org file +#+begin_src emacs-lisp + (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))) + + +#+end_src + +Define sections in roam. +#+begin_src emacs-lisp + (setq org-roam-mode-sections + '(org-roam-backlinks-section + org-roam-reflinks-section + org-roam-unlinked-references-section)) +#+end_src + +*** Link checking +Here we have custom functions, mimicking the ~zk~ cli. +This functions check if an org file has an inserted link to itself. +#+begin_src emacs-lisp +(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")))))) + + +#+end_src + +Check links that dont point to an actual file +#+begin_src emacs-lisp +(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))))) +#+end_src +*** Hooks +Run the defined above functions before every org file save +#+begin_src emacs-lisp +(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) +#+end_src +*** Maps +Define mappings +#+begin_src emacs-lisp + (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 + +#+end_src +** ox-html +~ox-html~ is a way to convert org files into html. +#+begin_src emacs-lisp +(with-eval-after-load 'ox-html + (setq org-html-xml-declaration nil + org-html-doctype "html5" + org-html-html5-fancy t +#+end_src + +Dont use ox's default html style +#+begin_src emacs-lisp + org-html-head-include-default-style nil +#+end_src + +Dont postamble in generated html +#+begin_src emacs-lisp + org-html-postamble nil)) +#+end_src + +** org-roam-ui +~org-roam-ui~ makes a Obsidian-like graph available in the browser. +It makes a pretty graph of all your notes and puts it at http://localhost:35901. + +Required websocket +#+begin_src emacs-lisp +(use-package! websocket :after org-roam) +#+end_src + +org-roam config +#+begin_src emacs-lisp +(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 +)) +#+end_src +** org-appear +Org appear makes it so that inline code blocks (=~~=), words marked verbatim (====) and (hyper)link syntax hide when viewing the file and appear when hovered on for easy editing. +for example =[[id:xqyz][emacs]]= will become =emacs= when viewing the file, but turn into the original when the cursor is over the text. +#+begin_src emacs-lisp +(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)) +#+end_src + +* Eww +~Eww... What browser is that girl using?~ + +~eww~ (Emacs Web WOWser) is, well, a web browser in Emacs. +It only renders HTML and tries its best to render CSS, so javascript is out of the question (hooray!) + +emms is fine on its own, but i have a config to make the experience better. +Here we define what to search with, for me this is Ecosia. +#+begin_src emacs-lisp +(setq eww-search-prefix "https://ecosia.org/search?q=") +#+end_src + +Where eww downloads files to. +#+begin_src emacs-lisp +(setq eww-download-directory (expand-file-name "~/Downloads/")) +#+end_src +** Functions +Open a link in mpv +#+begin_src emacs-lisp +(defun my-browse-url-mpv (url &rest _args) + "Open URL in mpv." + (start-process "mpv" nil "mpv" url)) +#+end_src + +Open a url in pdf-tools +#+begin_src emacs-lisp +(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))) +#+end_src + +Download an image and put it into ~eww-download-directory~ +#+begin_src emacs-lisp +(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))))) +#+end_src + +** Config :: Misc +Use the functions defined above when opening specific links +#+begin_src emacs-lisp +(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))) + +#+end_src + +Open a url in a secondary program, in my case ~Vivaldi~ +#+begin_src emacs-lisp +(setq browse-url-secondary-browser-function 'browse-url-generic + browse-url-generic-program "vivaldi") +#+end_src + +** UI/UX settings +#+begin_src emacs-lisp +(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) +#+end_src + +** Keybindings +#+begin_src emacs-lisp +(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) +#+end_src + + +* TODO Elpher +~Elpher Leaves Protocols Hanging, Eternally Relevant~ + + +* Packages +~The ones that dont belong~ + +These packages are (mostly) defined in ~packages.el~ and configured here. +** TODO mosey +Mosey lets you ~Mosey down~ (get it?) to different points in a code block. +#+begin_src emacs-lisp +(use-package! mosey + :commands (mosey-forward mosey-backward + mosey-forward-bounce mosey-backward-bounce + mosey-forward-cycle mosey-backward-cycle)) +#+end_src + +*** Keybinds +Keybinds for mosey, under K because m was taken by localleader bindings +#+begin_src emacs-lisp +(map! :leader + (:prefix ("k" . "mosey") + :desc "Mosey backward" "a" #'mosey-backward-bounce + :desc "Mosey forward" "e" #'mosey-forward-bounce)) +#+end_src + +** aggressive-indent +~aggressive-indent~ is a package that makes sure every line is indented properly. +It follows its own indentation, and forces (very aggressively) for lines to stay on there, live, while editing. +#+begin_src emacs-lisp +(use-package! aggressive-indent + :config + (global-aggressive-indent-mode 1)) ; use aggressive-indent everywhere +#+end_src + +** Woman +~woman~ is a way to view man pages straight in Emacs, without shelling out to the actual ~man~ binary, it stands for ~without man~ +Because i use Helm, im using the pre-configured Helm version +#+begin_src emacs-lisp +(map! + :leader + :prefix "o" + :desc "Woman" "w" #'helm-man-woman) +#+end_src + +** Dired +~Dired~ (Directory editor) is a way to, well, edit directories (and files!) in Emacs. +This is similar to ~oil.nvim~ +These are only bindings as dired is pre-installed on Emacs. +#+begin_src emacs-lisp +(map! + :leader + :prefix "d" + :desc "Dired" "d" #'dired + :desc "Dired here" "h" #'dired-jump) +#+end_src +~dired~ prompts for the directory to open first, while ~dired-jump~ opens dired in the current directory, pretty neat. + +* Evil +~Mapping at its finest~ +EVIl mode emulates VIM bindings in Emacs. + +Remove ~evil-snipe~ as it conflicts with other bindings +#+begin_src emacs-lisp +(remove-hook 'doom-first-input-hook #'evil-snipe-mode) +#+end_src + + +** Colemak +The biggest block for last. +This is a custom mapping i made for EVIl mode that takes the bindings from [[https://github.com/kalbasit/vim-colemak][kalbasit/vim-colemak]] and puts them into Emacs. +I plan on packaging this to [[https://melpa.org][MELPA]] soon. + +Make ~o~ go right in org mode (previously ~inserted on newline~) +#+begin_src emacs-lisp +(after! evil-org + (evil-define-key 'normal evil-org-mode-map + "o" #'evil-forward-char)) +#+end_src + +*** Main bindings +#+begin_src emacs-lisp +(evil-define-key '(normal visual operator) 'global + "n" 'evil-backward-char + "e" 'evil-next-line + "i" 'evil-previous-line + "o" 'evil-forward-char) + #+end_src +*** Motion +#+begin_src emacs-lisp +(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)) + + +#+end_src +*** Inserting +#+begin_src emacs-lisp +(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) +#+end_src +*** Changing +#+begin_src emacs-lisp +(evil-define-key '(normal visual) 'global + "w" 'evil-change + "W" 'evil-change-line) + + +#+end_src +*** Editing +#+begin_src emacs-lisp +(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) +#+end_src +*** TODO Undo +Doesnt work in org files +#+begin_src emacs-lisp +(evil-define-key 'normal 'global + "z" 'evil-undo + "Z" 'evil-redo) + + +#+end_src +*** Visual +#+begin_src emacs-lisp +(evil-define-key 'normal 'global + "a" 'evil-visual-char + "A" 'evil-visual-line + "ga" 'evil-visual-restore) + + +#+end_src +*** Find/Search +#+begin_src emacs-lisp +(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) + + +#+end_src +*** Inner change +#+begin_src emacs-lisp +(with-eval-after-load 'evil + (evil-define-key '(operator visual) 'global "r" evil-inner-text-objects-map)) + +#+end_src +*** Scroll +#+begin_src emacs-lisp +(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) + + +#+end_src +*** Lookup +#+begin_src emacs-lisp +(evil-define-key 'normal 'global + "gK" 'evil-lookup) + + +#+end_src +*** Window management +#+begin_src emacs-lisp +(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) + +#+end_src diff --git a/doom/.config/doom/init.el b/doom/.config/doom/init.el index 5862c74..394574f 100644 --- a/doom/.config/doom/init.el +++ b/doom/.config/doom/init.el @@ -144,7 +144,7 @@ ;;nix ; I hereby declare "nix geht mehr!" ;;ocaml ; an objective camel ;;odin ; C, minus its footguns - (org +roam) ; organize your plain life in plain text + (org +roam +pretty) ; organize your plain life in plain text php ; perl's insecure younger brother ;;plantuml ; diagrams for confusing people more ;;graphviz ; diagrams for confusing yourself even more @@ -182,7 +182,7 @@ ;;(rss +org) ; emacs as an RSS reader :config - ;;literate + literate (default +bindings +smartparens)) ;; If you're a dark-mode user who suffers from the "flash of white Emacs" when diff --git a/doom/.config/doom/splash.el b/doom/.config/doom/splash.el new file mode 100644 index 0000000..e61adbd --- /dev/null +++ b/doom/.config/doom/splash.el @@ -0,0 +1,57 @@ +;;; $DOOMDIR/splash.el -*- lexical-binding: t; -*- + + +(defun splash--center (str width) + "Return STR centered in WIDTH columns." + (let ((pad (max 0 (/ (- width (string-width str)) 2)))) + (concat (make-string pad ?\s) str))) + +(defun splash-screen () + "Show the splash screen." + (interactive) + (let ((buf (get-buffer-create "*splash*"))) + (with-current-buffer buf + (let ((inhibit-read-only t)) + (erase-buffer) + (when (one-window-p) + (setq mode-line-format nil)) + (setq cursor-type nil) + (let* ((height (- (window-body-height nil) 1)) + (width (window-body-width nil)) + (pad-top (- (/ height 2) 1)) + (pad-bottom (- height (/ height 2) 3)) + (emacs-str (format "GNU Emacs version %d.%d" + emacs-major-version + emacs-minor-version))) + (insert (make-string pad-top ?\n)) + (insert (splash--center "www.gnu.org" width) "\n") + (insert (splash--center emacs-str width) "\n") + (insert (splash--center "A free/libre editor" width) "\n") + (insert (make-string pad-bottom ?\n)) + (insert (splash--center "GNU Emacs comes with ABSOLUTELY NO WARRANTY" width) "\n") + (insert (splash--center "Copyright (C) 2026 Free Software Foundation, Inc." width) "\n")) + (goto-char (point-min)) + (read-only-mode 1) + (use-local-map (make-sparse-keymap)))))) + +(defun splash-screen-kill () + "Kill the splash buffer." + (interactive) + (when (get-buffer "*splash*") + (kill-buffer "*splash*"))) + +(if (daemonp) + (add-hook 'server-after-make-frame-hook + (lambda () + (run-with-timer 0.15 nil #'splash-screen))) + (when (and (not (member "-no-splash" command-line-args)) + (not (member "--file" command-line-args)) + (not (member "--insert" command-line-args)) + (not (member "--find-file" command-line-args))) + (add-hook 'window-setup-hook #'splash-screen) + (setq inhibit-startup-screen t + inhibit-startup-message t + inhibit-startup-echo-area-message t))) + +(provide 'splash-screen) +;;; splash.el ends here -- cgit v1.2.3