From 58ea0e997a0a60f27c317a5934ce1daac39edd22 Mon Sep 17 00:00:00 2001 From: Magdalena Szweda Date: Wed, 30 Sep 2026 21:22:23 +0200 Subject: stuff --- doom/.config/doom/config.el | 62 +- doom/.config/doom/config.org | 105 +++- doom/.config/doom/config.org.bak | 1219 ++++++++++++++++++++++++++++++++++++++ doom/.config/doom/packages.el | 3 + fish/.config/fish/config.fish | 1 + fish/.config/fish/fish_variables | 2 + 6 files changed, 1366 insertions(+), 26 deletions(-) create mode 100644 doom/.config/doom/config.org.bak diff --git a/doom/.config/doom/config.el b/doom/.config/doom/config.el index e9c9fc7..cad7dd4 100644 --- a/doom/.config/doom/config.el +++ b/doom/.config/doom/config.el @@ -18,7 +18,7 @@ (setq custom-safe-themes t) -(setq doom-font (font-spec :family "Berkeley Mono" :size 12.0)) +(setq doom-font (font-spec :family "Berkeley Mono" :size 13.0)) (setq display-line-numbers-type t) @@ -66,14 +66,21 @@ :hook (prog-mode . eglot-ensure)) +(use-package! eglot-booster + :after eglot + :config (eglot-booster-mode)) + (after! eglot - (cl-defmethod eglot-register-capability - (server (method (eql workspace/didChangeWatchedFiles)) id &key watchers) - nil) + (cl-defmethod eglot-register-capability + ((_server eglot-lsp-server) + (method (eql workspace/didChangeWatchedFiles)) + _id + &key _watchers) + nil) (add-to-list 'eglot-server-programs '((typescript-ts-mode javascript-mode) - . ("oxlint" "--lsp")))) + . ("emacs-lsp-booster" "--" "oxlint" "--lsp")))) (setq eglot-sync-connect nil eglot-connect-timeout 60) @@ -109,7 +116,7 @@ '("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))) + (setf (alist-get mode apheleia-mode-alist) 'oxfmt))) (use-package! pinentry :config @@ -259,6 +266,41 @@ emms-cache-file (concat doom-cache-dir "emms-cache")) (map! :map emms-browser-mode-map :n "RET" #'emms-browser-add-tracks-and-play)) +(map! + :leader + :prefix "v" + :desc "vc-edit-next-command" "!" #'vc-edit-next-command + :desc "diff-hl-show-hunk" "*" #'diff-hl-show-hunk + :desc "vc-update" "+" #'vc-update + :desc "diff-hl-goto-hunk" "=" #'diff-hl-diff-goto-hunk + :desc "vc-revert" "@" #'vc-revert + :desc "vc-update-change-log" "a" #'vc-update-change-log + ;; ADD b BINDINGS (branch) + :desc "vc-dir" "d" #'vc-dir + :desc "vc-root-diff" "D" #'vc-root-diff + ;; ADD E BINDINGS + :desc "annotate" "g" #'vc-annotate + :desc "ignore" "G" #'vc-ignore + :desc "region history" "h" #'vc-region-history + :desc "register" "i" #'vc-register + :desc "root log incoming" "I" #'vc-root-log-incoming + :desc "print log" "l" #'vc-print-log + :desc "print root log" "L" #'vc-print-root-log + :desc "merge" "m" #'vc-merge + ;; ADD M BINDINGS + :desc "diff revert hunk" "n" #'diff-hl-revert-hunk + :desc "root log outgoing" "O" #'vc-root-log-outgoing + :desc "push" "p" #'vc-push ; originally P + :desc "retrieve tag" "r" #'vc-retrieve-tag + :desc "rename file" "R" #'vc-rename-file + :desc "create tag" "s" #'vc-create-tag + :desc "stage dwim (diff hl)" "S" #'diff-hl-stage-dwim + ;; ADD T BINDINGS + :desc "vc revert" "u" #'vc-revert ; carried over from the original bindings (repeated by @) + :desc "vc next action" "v" #'vc-next-action ; run the next logical action + ;; ADD w BINDINGS + :desc "revision other window" "~" #'vc-revision-other-window) + (map! :leader :prefix "g m" @@ -267,6 +309,8 @@ emms-cache-file (concat doom-cache-dir "emms-cache")) :desc "New" "n" #'majutsu-new ; new jj rev :desc "Push" "p" #'majutsu-git-push) ; push to git +(use-package! vc-jj) + (setq org-directory "~/org/") (after! org @@ -296,6 +340,8 @@ org-confirm-babel-evaluate nil) (add-hook 'org-src-mode-hook #'eglot-ensure) +(setq org-element-use-cache nil) + (add-hook 'org-capture-mode-hook #'delete-other-windows) (add-hook 'org-capture-mode-hook (lambda () (set-window-dedicated-p (selected-window) nil))) @@ -487,7 +533,7 @@ org-html-postamble nil)) (map! :leader - :prefix "d" + :prefix ("d" . "dired") :desc "Dired" "d" #'dired :desc "Dired here" "h" #'dired-jump) @@ -550,7 +596,7 @@ org-html-postamble nil)) "u" 'evil-forward-word-end "U" 'evil-forward-WORD-end "y" 'evil-forward-word-begin - "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) diff --git a/doom/.config/doom/config.org b/doom/.config/doom/config.org index e373e3a..daf16a9 100644 --- a/doom/.config/doom/config.org +++ b/doom/.config/doom/config.org @@ -1,7 +1,8 @@ #+TITLE: Doom Emacs configuration #+PROPERTY: header-args:emacs-lisp :tangle config.el * Foreword -Hello! This is my literate configuration for Doom Emacs. + +"Hello! This is my literate configuration for Doom Emacs." Why literate? because org is cool! I use Doom Emacs because it's easy, simple & easy to configure. This config will be ported into normal Emacs in the future, but im not planning that for now. @@ -44,9 +45,9 @@ By default, Emacs prompts 2 times when loading a theme, this is annoying so im g #+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!) +Sometimes i will use the Commit mono or Cozette! (sometimes!) #+begin_src emacs-lisp - (setq doom-font (font-spec :family "Berkeley Mono" :size 12.0)) + (setq doom-font (font-spec :family "Berkeley Mono" :size 13.0)) #+end_src Line numbers! And not relative! @@ -141,21 +142,34 @@ eglot-ensure makes sure that eglot is enabled and working when opening a prog-mo (prog-mode . eglot-ensure)) #+end_src -I copied this block from somewhere and have no idea what it does. +Then we can set up ~eglot-booster~, which adds ~emacs-lsp-booster~ integration into eglot. +emacs-lsp-booster, well, boosts lsp (with rust!) #+begin_src emacs-lisp - (after! eglot - (cl-defmethod eglot-register-capability - (server (method (eql workspace/didChangeWatchedFiles)) id &key watchers) - nil) +(use-package! eglot-booster + :after eglot + :config (eglot-booster-mode)) #+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 eglot-lsp-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")))) +(add-to-list 'eglot-server-programs + '((typescript-ts-mode javascript-mode) + . ("emacs-lsp-booster" "--" "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. @@ -224,12 +238,8 @@ We can then add a new apheleia formatter, in this case oxfmt. #+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)) +(dolist (mode '(html-mode mhtml-mode web-mode css-mode)) (setf (alist-get mode apheleia-mode-alist) 'oxfmt))) #+end_src @@ -527,6 +537,47 @@ This currently doesnt work. * Git ~LEAVE Emacs? You gotta be kidding.~ +** TODO vc :: maps +Mappings for vc. +By default, vc bindings are under ~C-x v~, but thats annoying, i'll be binding it under ~SPC v~ +I tried my best to match these to the default bindings under ~C-x v~ + +#+begin_src emacs-lisp + (map! + :leader + :prefix "v" + :desc "vc-edit-next-command" "!" #'vc-edit-next-command + :desc "diff-hl-show-hunk" "*" #'diff-hl-show-hunk + :desc "vc-update" "+" #'vc-update + :desc "diff-hl-goto-hunk" "=" #'diff-hl-diff-goto-hunk + :desc "vc-revert" "@" #'vc-revert + :desc "vc-update-change-log" "a" #'vc-update-change-log + ;; ADD b BINDINGS (branch) + :desc "vc-dir" "d" #'vc-dir + :desc "vc-root-diff" "D" #'vc-root-diff + ;; ADD E BINDINGS + :desc "annotate" "g" #'vc-annotate + :desc "ignore" "G" #'vc-ignore + :desc "region history" "h" #'vc-region-history + :desc "register" "i" #'vc-register + :desc "root log incoming" "I" #'vc-root-log-incoming + :desc "print log" "l" #'vc-print-log + :desc "print root log" "L" #'vc-print-root-log + :desc "merge" "m" #'vc-merge + ;; ADD M BINDINGS + :desc "diff revert hunk" "n" #'diff-hl-revert-hunk + :desc "root log outgoing" "O" #'vc-root-log-outgoing + :desc "push" "p" #'vc-push ; originally P + :desc "retrieve tag" "r" #'vc-retrieve-tag + :desc "rename file" "R" #'vc-rename-file + :desc "create tag" "s" #'vc-create-tag + :desc "stage dwim (diff hl)" "S" #'diff-hl-stage-dwim + ;; ADD T BINDINGS + :desc "vc revert" "u" #'vc-revert ; carried over from the original bindings (repeated by @) + :desc "vc next action" "v" #'vc-next-action ; run the next logical action + ;; ADD w BINDINGS + :desc "revision other window" "~" #'vc-revision-other-window) +#+end_src ** Majutsu I use the JuJutsu version control system. I am an old user of ~magit~. Why not use magit for JJ? @@ -543,6 +594,19 @@ Open the main majutsu buffer. :desc "Push" "p" #'majutsu-git-push) ; push to git #+end_src +** vc-jj +~vc-jj~ adds jujutsu integration to Emacs's ~vc~! +#+begin_src emacs-lisp :tangle no + ;; required in packages.el + ;; (package! vc-jj) +#+END_SRC + +Then, we actually enable it. +#+begin_src emacs-lisp + (use-package! vc-jj) +#+end_src +~vc-jj~ configures itself into vc by itself, no further configuration is needed + * Org ~Protesting for Org README support.~ Org is Emacs's version of markdown, and is what this file is written in. @@ -594,6 +658,11 @@ After that, we still need to add Eglot integration. #+begin_src emacs-lisp (add-hook 'org-src-mode-hook #'eglot-ensure) #+end_src + +There's a bug that hits org-lint & poly-org & flycheck about org element's cache, so lets just disable it. +#+begin_src emacs-lisp + (setq org-element-use-cache nil) +#+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. @@ -933,7 +1002,7 @@ These are only bindings as dired is pre-installed on Emacs. #+begin_src emacs-lisp (map! :leader - :prefix "d" + :prefix ("d" . "dired") :desc "Dired" "d" #'dired :desc "Dired here" "h" #'dired-jump) #+end_src @@ -1048,7 +1117,7 @@ Make ~o~ go right in org mode (previously ~inserted on newline~) "u" 'evil-forward-word-end "U" 'evil-forward-WORD-end "y" 'evil-forward-word-begin - "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) diff --git a/doom/.config/doom/config.org.bak b/doom/.config/doom/config.org.bak new file mode 100644 index 0000000..c2ae151 --- /dev/null +++ b/doom/.config/doom/config.org.bak @@ -0,0 +1,1219 @@ +#+TITLE: Doom Emacs configuration +#+PROPERTY: header-args:emacs-lisp :tangle config.el +* Foreword +Hello! This is my literate configuration for Doom Emacs. +Why literate? because org is cool! +I use Doom Emacs because it's easy, simple & easy to configure. +This config will be ported into normal Emacs in the future, but im not planning that for now. +* 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 + +By default, Emacs prompts 2 times when loading a theme, this is annoying so im getting rid of it. +#+begin_src emacs-lisp + (setq custom-safe-themes t) +#+end_src +** Font +I use the completely not pirated ~Berkeley Mono~ font. I really like it. +Sometimes i will use the Commit mono or Cozette! (sometimes!) +#+begin_src emacs-lisp + (setq doom-font (font-spec :family "Berkeley Mono" :size 13.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 + +mood-line is a nice & simple modeline for emacs! +#+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 + +** Zen +the ~zen~ option in Doom Emacs enables ~writeroom~ mode on toggle. +~writeroom~ centers the buffer, makes it bigger and lets you type away without distractions. +By default, entering ~writeroom~ mode (which i will continue to call ~zen~ mode) changes the typeface in the buffer. +I don't like that, especially when im editing source blocks (e.g here). Let's turn it off. +#+begin_src emacs-lisp + (setq +zen-mixed-pitch-modes '()) +#+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 + +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 + +Then we can set up ~eglot-booster~, which adds ~emacs-lsp-booster~ integration into eglot. +emacs-lsp-booster, well, boosts lsp (with rust!) +#+begin_src emacs-lisp +(use-package! eglot-booster + :after eglot + :config (eglot-booster-mode)) +#+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 eglot-lsp-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) + . ("emacs-lsp-booster" "--" "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: +#+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). +First we set up pinentry. +#+begin_src emacs-lisp + (use-package! pinentry + :config + (pinentry-start)) + (setq epg-pinentry-mode 'loopback) +#+end_src +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 + '("B9CF59FE57835F89ECB33FD417CA809770F85511") + 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 + +By default, Gnus puts entries newest last, let's reverse it. +#+begin_src emacs-lisp +(setq gnus-thread-sort-functions + '((not gnus-thread-sort-by-date))) + +(setq gnus-subthread-sort-functions + '((not gnus-thread-sort-by-date))) +(setq gnus-thread-sort-most-recent-first t) +#+end_src + +What Gnus also does by default is ask to read the .newsrc file, this file is basically an auto-save, 90% of the time you want to read it. +Let's just disable the prompt on every Gnus startup. +#+begin_src emacs-lisp + (setq gnus-always-read-dribble-file nil) +#+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") + ("wildebeest@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 +#+begin_quote +~Music to my ears~ +#+end_quote + +EMMS, the Emacs MultiMedia System (but mostly its just used for music). +Now, emms has this issue where mpd and the emms cache fall out of sync. This is a documented issue so lets make them catch up by default. + +Let's make a quick helper function. +#+begin_src emacs-lisp +(defun emms--wait-for-mpd-update (callback) + "Poll MPD status until updating_db clears, then call CALLBACK." + (emms-player-mpd-get-status + callback + (lambda (callback info) + (if (assoc "updating_db" info) + (run-with-timer 0.5 nil #'emms--wait-for-mpd-update callback) + (funcall callback))))) +#+end_src + +And wire it into emms +#+BEGIN_SRC emacs-lisp +(defun emms-full-resync () + "Update MPD's db, then pull it into EMMS's cache, then rebuild the browser." + (interactive) + (message "emms: starting mpd db update...") + (emms-player-mpd-update-all) + (emms--wait-for-mpd-update + (lambda () + (emms-cache-set-from-mpd-all) + (dolist (buf (buffer-list)) + (with-current-buffer buf + (when (derived-mode-p 'emms-browser-mode) + (revert-buffer)))) + (emms-browser) + (message "emms: resync done")))) +#+END_SRC + +Declare the package block and set up the commands. +~: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 emms-player-mpd-update-all emms-cache-set-from-mpd-all) +#+end_src + +Configure the mappings for EMMS +~: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-full-resync + :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.~ +** TODO vc :: maps +Mappings for vc. +By default, vc bindings are under ~C-x v~, but thats annoying, i'll be binding it under ~SPC v~ +I tried my best to match these to the default bindings under ~C-x v~ + +#+begin_src emacs-lisp + (map! + :leader + :prefix "v" + :desc "vc-edit-next-command" "!" #'vc-edit-next-command + :desc "diff-hl-show-hunk" "*" #'diff-hl-show-hunk + :desc "vc-update" "+" #'vc-update + :desc "diff-hl-goto-hunk" "=" #'diff-hl-diff-goto-hunk + :desc "vc-revert" "@" #'vc-revert + :desc "vc-update-change-log" "a" #'vc-update-change-log + ;; ADD b BINDINGS (branch) + :desc "vc-dir" "d" #'vc-dir + :desc "vc-root-diff" "D" #'vc-root-diff + ;; ADD E BINDINGS + :desc "annotate" "g" #'vc-annotate + :desc "ignore" "G" #'vc-ignore + :desc "region history" "h" #'vc-region-history + :desc "register" "i" #'vc-register + :desc "root log incoming" "I" #'vc-root-log-incoming + :desc "print log" "l" #'vc-print-log + :desc "print root log" "L" #'vc-print-root-log + :desc "merge" "m" #'vc-merge + ;; ADD M BINDINGS + :desc "diff revert hunk" "n" #'diff-hl-revert-hunk + :desc "root log outgoing" "O" #'vc-root-log-outgoing + :desc "push" "p" #'vc-push ; originally P + :desc "retrieve tag" "r" #'vc-retrieve-tag + :desc "rename file" "R" #'vc-rename-file + :desc "create tag" "s" #'vc-create-tag + :desc "stage dwim (diff hl)" #'diff-hl-stage-dwim + ;; ADD T BINDINGS + :desc "vc revert" "u" #'vc-revert ; carried over from the original bindings (repeated by @) + :desc "vc next action" "v" #'vc-next-action ; run the next logical action + ;; ADD w BINDINGS + :desc "revision other window" "~" #'vc-revision-other-window) +#+end_src +** 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" "m" #'majutsu ; default majutsu buffer + :desc "Describe" "d" #'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 + +** vc-jj +~vc-jj~ adds jujutsu integration to Emacs's ~vc~! +#+begin_src emacs-lisp :tangle no + ;; required in packages.el + ;; (package! vc-jj) +#+END_SRC + +~vc-jj~ configures itself into vc by itself, no further configuration is needed + +* 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-folded t ; fold headers on startup + org-pretty-entities t + org-hide-emphasis-markers t + org-auto-align-tags nil + org-tags-column 0 + org-catch-invisible-edits 'show-and-error + org-agenda-tags-column 0 + org-capture-templates-contexts nil + org-insert-heading-respect-content t + org-special-ctrl-a/e t + org-return-follows-link t +#+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 +** poly-org +~poly-org~ lets you use LSP and autocompletion in org code blocks without pressing ~C-c '~ +By default, org lets you 'enter' code blocks with ~C-c '~ and have actual autocompletion/LSP features. +But, typing that every block is annoying (especially with a literate config), that's why ~poly-org~ does the same thing* as ~C-c '~, but it happens when +the cursor hovers over a block. +#+begin_src emacs-lisp + (use-package! poly-org + :hook (org-mode . poly-org-mode)) +#+end_src + +After that, we still need to add Eglot integration. +#+begin_src emacs-lisp + (add-hook 'org-src-mode-hook #'eglot-ensure) +#+end_src + +There's a bug that hits org-lint & poly-org & flycheck about org element's cache, so lets just disable it. +#+begin_src emacs-lisp + (setq org-element-use-cache nil) +#+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 +#+end_src +The org graph requires Graphviz and the ~dot~ executable +#+begin_src emacs-lisp + :desc "Graph" "g" #'org-roam-graph ; graph of every note +#+end_src +#+begin_src emacs-lisp + :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 +** org-modern-indent +Because doom's org ~+pretty~ flag turns on org modern, and org-modern is incompatible with ~org-startup-indented~, we use the ~org-indent-modern~ package +#+begin_src emacs-lisp +(use-package! org-modern-indent + :defer t +:hook (org-mode . org-modern-indent-mode)) +#+end_src +* Eww +#+begin_quote +Eww... What browser is that girl using? +#+end_quote + +~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!) + +~eww~ 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 + +Let's make ~eww~ go into readable mode on page enter. +#+begin_src emacs-lisp + (add-hook 'eww-after-render-hook #'eww-readable) +#+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 + +* Elpher +#+begin_quote +Elpher? I hardly know her! +#+end_quote + +Elpher is a way to use the Gemini and Gopher protocols in Emacs. +#+begin_src emacs-lisp +(use-package! elpher) +#+end_src +There's not much config needed except 1 (one) binding +#+begin_src emacs-lisp + (map! + :leader + :prefix "o g" + :desc "Elpher" "e" #'elpher + :desc "Browse Elpher" "b" #'elpher-browse-url-elpher) +#+end_src +* Packages +#+BEGIN_QUOTE +The ones that dont belong +#+END_QUOTE +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 +TODO: make this work properly and not just go to the start/end of line +*** 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 + +** 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~ +Let's map this to a mnemonic binding, in this case ~Open Woman~ + +#+begin_src emacs-lisp + (map! + :leader + :prefix "o" + :desc "Woman" "w" #'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 ("Dired" . "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. +** eat +~eat~ (emulate a terminal) is a terminal emulator, in elisp, for emacs! +It is not available as a doom emacs module, so we declare it manually. +#+begin_src emacs-lisp + (use-package! eat + :defer t) +#+end_src + +Then we add bindings for ~eat~ as to not have to run ~M-x~ everytime. +#+begin_src emacs-lisp + (map! + :leader + :prefix "o" + :desc "Open Eat" "e" #'eat-other-window) ; dont steal the current window +#+end_src + +** nov.el +#+begin_quote +This is pushing it. +#+end_quote + +nov.el is a way to read EPUB's in Emacs! because why buy a kindle if you have GNU? +Requires ~(package! nov)~ in packages.el (doom) +#+begin_src emacs-lisp +(use-package! nov + :mode ("\\.epub\\'" . nov-mode) + :config + (setq nov-text-width 80 + nov-variable-pitch t) + (add-hook 'nov-mode-hook + (lambda () + (face-remap-add-relative 'variable-pitch + :family "Georgia" :height 1.3))) ; different font for reading + (add-hook 'nov-mode-hook #'writeroom-mode) ; center text & stuff + #+end_src + + Now let's add some nov mappings + #+begin_src emacs-lisp + (map! :map nov-mode-map + :n "i" #'nov-scroll-up ; scroll roughly a page up + :n "e" #'nov-scroll-down ; scroll roughly a page down + :n "]" #'nov-next-document + :n "[" #'nov-previous-document + :n "t" #'nov-goto-toc)) +#+end_src + +* Tramp + +Tramp is a way to edit files via SSH and root owned files in Emacs. +This section is purely used to help me with editing root owned files, without calling ~doas emacs~ and losing my config +#+begin_src emacs-lisp +(with-eval-after-load 'tramp + (add-to-list 'tramp-methods + '("doas" + (tramp-login-program "doas") + (tramp-login-args (("-u" "%u") ("-s"))) + (tramp-remote-shell "/bin/sh") + (tramp-remote-shell-args ("-c")) + (tramp-connection-timeout 10)))) +#+end_src +* 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 + +** Lispy +~lispy~[fn:1] is a way to run vim motions in a S-exp aware way. +As an example , running ~D~ on +~(message "Get rid of |everything" a b (+ 1 2))~, where ~|~ is the point would ruin the S-exp, but with ~lispy~, this turns into: +~(message "Get rid of ")~ +Pretty neat, huh? +#+begin_src emacs-lisp + (use-package lispyville + :init + (general-add-hook '(emacs-lisp-mode-hook lisp-mode-hook) #'lispyville-mode) ;; lispy lisps + :config + (lispyville-set-key-theme '(operators c-w additional))) +#+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 + +* Footnotes + +[fn:1] +The actual vim motion part is provided by ~lispyville~, which adds evil support into diff --git a/doom/.config/doom/packages.el b/doom/.config/doom/packages.el index b8e5cb9..171b61f 100644 --- a/doom/.config/doom/packages.el +++ b/doom/.config/doom/packages.el @@ -17,3 +17,6 @@ :recipe (:host github :repo "jdtsmith/org-modern-indent")) (package! nov) (package! pinentry) +(package! eglot-booster + :recipe (:host github :repo "jdtsmith/eglot-booster")) +(package! vc-jj) diff --git a/fish/.config/fish/config.fish b/fish/.config/fish/config.fish index 52f94a0..65d275a 100644 --- a/fish/.config/fish/config.fish +++ b/fish/.config/fish/config.fish @@ -7,6 +7,7 @@ alias ll "ls -la" alias vial Vial alias sudo doas +alias sober "flatpak run org.vinegarhq.Sober" # set set -gx EDITOR emacs # Functions diff --git a/fish/.config/fish/fish_variables b/fish/.config/fish/fish_variables index abef2e6..bab0bbf 100644 --- a/fish/.config/fish/fish_variables +++ b/fish/.config/fish/fish_variables @@ -1,6 +1,8 @@ # This file contains fish universal variable definitions. # VERSION: 3.0 SETUVAR --export DOOMDIR:/home/hi/\x2econfig/doom/ +SETUVAR --export MANPAGER:/usr/sbin/more +SETUVAR --export PAGER:/usr/sbin/more SETUVAR --export ZK_NOTEBOOK_DIR:/home/sophie/notes/ SETUVAR __fish_initialized:4300 SETUVAR _fisher_jorgebucaran_2F_fisher_files:\x7e/\x2econfig/fish/functions/fisher\x2efish\x1e\x7e/\x2econfig/fish/completions/fisher\x2efish -- cgit v1.2.3