diff options
Diffstat (limited to 'doom/.config/doom/config.org')
| -rw-r--r-- | doom/.config/doom/config.org | 1604 |
1 files changed, 0 insertions, 1604 deletions
diff --git a/doom/.config/doom/config.org b/doom/.config/doom/config.org deleted file mode 100644 index 28d95bb..0000000 --- a/doom/.config/doom/config.org +++ /dev/null @@ -1,1604 +0,0 @@ -#+TITLE: Literate DOOM Emacs configuration -#+begin_src emacs-lisp :tangle ~/.config/doom/emms-player-xmms2.el -;;; emms-player-xmms2.el --- XMMS2 player for EMMS -*- lexical-binding: t; -*- - -Emacs is a great operating system. -But every operating system has 1 essential line of code. -For us, this line of code is... (drumroll please) -#+begin_src emacs-lisp - ;;; $DOOMDIR/config.el -*- lexical-binding: t; -*- -#+end_src - -Almost every ~(use-package!)~ block in this literate configuration has a ~(package!)~ block before it, which is tangled into ~$DOOMDIR/packages.el~. This is how Doom Emacs installs it's packages. - - -* TODO Splash screen - -Here we load a custom splash screen. -I still have to put the splash screen source in this org file, but that'll come later -#+begin_src emacs-lisp -(load! "splash") -(defun +splash-initial-buffer () - (splash-screen) - (get-buffer "*splash*")) - -(setq doom-fallback-buffer-name "*splash*" ; make the splash screen be un-killable - initial-buffer-choice #'+splash-initial-buffer) ; appear on emacs startup - -(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://git.roughlynamed.net/evergarden.git][git.roughlynamed/net/evergarden.git]], 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. - -For this to work, we need modus & ef themes installed. -Doric themes are also nice. -#+begin_src emacs-lisp :tangle ~/.config/doom/packages.el -(package! modus-themes) -(package! ef-themes) -(package! doric-themes) -#+end_src - -#+begin_src emacs-lisp -(add-to-list 'custom-theme-load-path - "~/.config/doom/extra-themes/") -;; (setq doom-theme 'modus-vivendi) -;; (setq doom-theme 'doric-oak) -(setq doom-theme 'doric-obsidian) -;; (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 :tangle ~/.config/doom/packages.el -;; (package! mood-line) -#+end_src - -#+begin_src emacs-lisp -;; (use-package! mood-line -;; :config -;; (mood-line-mode) -;; :custom -;; (mood-line-glyph-alist mood-line-glyphs-fira-code)) -#+end_src -The above is commented if the below is in action. -I might try out the default Emacs modeline for a bit sometime, or maybe spacemacs' ~spaceline~ - -** Minions -The default Emacs modeline, by default, spills out EVERY minor & major mode into the modeline. -That's kind of yucky, so the ~minions~ package fixes it by hiding most of them & having a menu for which to show. -#+begin_src emacs-lisp :tangle ~/.config/doom/packages.el -(package! minions) -#+end_src - -Now, let's configure it! -#+begin_src emacs-lisp -(use-package! minions - :config - (minions-mode 1)) -#+end_src - -...Yea that's 'bout it. -** 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 :tangle ~/.config/doom/packages.el -(package! breadcrumb) -#+end_src - -#+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, or read via ~nov.el~ easier. -By default, entering ~writeroom~ 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 -** vertico-carousel -~vertico~ is the equivalent of nvim's ~telescope~ in Emacs. -#+begin_quote -~vertico-carousel~ is a display extension for Vertico. It always shows -the currently selected candidate on the first line of the candidate list, -then displays the following candidates below it, cycling from the end back -to the beginning. --- vertico-carousel README -#+end_quote - -#+begin_src emacs-lisp :tangle ~/.config/doom/packages.el -(package! vertico-carousel - :recipe (:host github :repo "kn66/vertico-carousel")) -#+end_src -#+begin_src emacs-lisp -(use-package! vertico-carousel - :config - (vertico-carousel-mode 1)) -#+end_src -* 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 "<f5>") #'my/hs-eval))) -#+end_src - -** HTML -HTML is a big part of my programming life. -There are, however, alot of modes for HTML (html-mode, web-mode, mhtml-mode). -These are all good, but the BEST one by far is ~mhtml-ts-mode~, it outcompetes almost all of the above. -#+begin_src emacs-lisp - (add-to-list 'major-mode-remap-alist '(html-mode . mhtml-ts-mode)) - (add-to-list 'major-mode-remap-alist '(mhtml-mode . mhtml-ts-mode)) -#+end_src - -web-mode rescans the whole altered block on every edit, which gets slow on HTML with big inline ~<script>~ and ~<style>~ blocks. -~mhtml-ts-mode~ is built in and tree-sitter based. It needs the html, css and javascript grammars, which ~M-x mhtml-ts-mode-install-parsers~ builds. - -Claim =.html= for it, and remap the other HTML modes to it. - -#+begin_src emacs-lisp -(add-to-list 'auto-mode-alist '("\\.html?\\'" . mhtml-ts-mode)) -(add-to-list 'major-mode-remap-alist '(html-mode . mhtml-ts-mode)) -(add-to-list 'major-mode-remap-alist '(mhtml-mode . mhtml-ts-mode)) -#+end_src - -Things like ~php~ or ~vue~ call ~web-mode~ directly, and ~mhtml-ts-mode~ doesnt understand those languages, so we make sure that -those languages get ~web-mode~ -#+begin_src emacs-lisp -(advice-add 'web-mode :around - (lambda (orig &rest args) - (if (or (null buffer-file-name) - (string-match-p "\\.html?\\'" buffer-file-name)) - (mhtml-ts-mode) - (apply orig args)))) -#+end_src -** Eglot -Eglot is, well, LSP for Emacs! -It bundles all your LSP's into one big package so you dont have to install everything manually -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. -#+begin_src emacs-lisp :tangle ~/.config/doom/packages.el -(package! eglot-booster - :recipe (:host github :repo "jdtsmith/eglot-booster")) -#+end_src -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 (mhtml-ts-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 apheleia: - #+begin_src emacs-lisp - (dolist (mode '(mhtml-ts-mode html-mode mhtml-mode web-mode css-mode)) - (setf (alist-get mode apheleia-mode-alist) 'oxfmt))) - #+end_src - Let's also hook mhtml-ts-mode into apheleia -#+begin_src emacs-lisp - (add-hook 'mhtml-ts-mode-hook #'apheleia-mode) -#+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 install & set up pinentry. -#+begin_src emacs-lisp :tangle ~/.config/doom/packages.el -(package! pinentry) -#+end_src - -#+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 - -While we're at it, let's make opening gnus easier. -#+begin_src emacs-lisp -(map! - :leader - :prefix "o" - :desc "Mail" "m" #'gnus) -#+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 :tangle ~/.config/doom/packages.el -(package! jabber) -#+end_src -#+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 - -* TODO EMMS -#+begin_quote -~Music to my ears~ -#+end_quote -** TODO EMMS xmms2 - -This is a project for adding xmms2 support into the Emacs MultiMedia System. -I plan on getting this into Savannah, then GNU ELPA, or having it merged with the official EMMS repository. - -And now, ladies & gentlemen, i present to you a bunch of self-documenting code im too lazy to split up into different source blocks!!! -#+begin_src emacs-lisp :tangle ~/.config/doom/emms-player-xmms2.el -;;; emms-player-xmms2.el --- XMMS2 player for EMMS -*- lexical-binding: t; -*- - -;; Setup: -;; (add-to-list 'load-path "/dir/containing/this/file") -;; (require 'emms-player-xmms2) -;; (setq emms-player-list '(emms-player-xmms2)) - -(require 'cl-lib) -(require 'dbus) -(require 'emms-player-simple) - -(defgroup emms-player-xmms2 nil - "EMMS player for XMMS2." - :group 'emms-player - :prefix "emms-player-xmms2-") - -(defcustom emms-player-xmms2-command "xmms2" - "The xmms2 CLI executable." - :type 'string) - -(defcustom emms-player-xmms2-mpris-service "org.mpris.MediaPlayer2.xmms2" - "D-Bus name owned by the xmms2 MPRIS bridge." - :type 'string) - -(defcustom emms-player-xmms2-check-interval 1 - "Seconds between playback checks." - :type 'number) - -(defcustom emms-player-xmms2 - (emms-player #'emms-player-xmms2-start - #'emms-player-xmms2-stop - #'emms-player-xmms2-playable-p) - "Parameters for the XMMS2 player." - :type '(cons symbol alist)) - -(emms-player-set emms-player-xmms2 'regex - (emms-player-simple-regexp - "ogg" "flac" "mp3" "wav" "opus" "m4a" "aac" "mod")) -(emms-player-set emms-player-xmms2 'pause 'emms-player-xmms2-pause) -(emms-player-set emms-player-xmms2 'resume 'emms-player-xmms2-resume) -(emms-player-set emms-player-xmms2 'seek 'emms-player-xmms2-seek) -(emms-player-set emms-player-xmms2 'seek-to 'emms-player-xmms2-seek-to) - -;;; State - -(defvar emms-player-xmms2--timer nil) -(defvar emms-player-xmms2--seen-playing nil - "Non-nil once XMMS2 has reported Playing/Paused since the last start. -Guards against reading a stale \"Stopped\" right after starting playback.") -(defvar emms-player-xmms2--synced nil - "File names last pushed into XMMS2's playlist, in order.") -(defvar emms-player-xmms2--tracks nil - "EMMS tracks mirrored in XMMS2's playlist, in the same order.") -(defvar emms-player-xmms2--pos nil - "1-based position XMMS2 was last known to be on.") - -;;; Helpers - -(defun emms-player-xmms2--run (&rest args) - "Run the xmms2 CLI with ARGS. Return non-nil on success." - (zerop (apply #'call-process emms-player-xmms2-command nil nil nil args))) - -(defun emms-player-xmms2--state () - "Return the MPRIS PlaybackStatus string, or nil if unreachable." - (ignore-errors - (dbus-get-property :session emms-player-xmms2-mpris-service - "/org/mpris/MediaPlayer2" - "org.mpris.MediaPlayer2.Player" "PlaybackStatus"))) - -(defun emms-player-xmms2--list-info () - "Return (CURRENT-POS . COUNT) parsed from `xmms2 list', or nil on failure. -CURRENT-POS is the 1-based position of the `->' entry, or nil." - (with-temp-buffer - (when (zerop (call-process emms-player-xmms2-command nil t nil "list")) - (let ((count 0) (pos nil)) - (goto-char (point-min)) - (while (re-search-forward - "^\\(->\\| \\)\\[\\([0-9]+\\)/[0-9]+\\]" nil t) - (setq count (1+ count)) - (when (string= (match-string 1) "->") - (setq pos (string-to-number (match-string 2))))) - (cons pos count))))) - -(defun emms-player-xmms2--name (track) - "The file name to hand to xmms2 for TRACK." - (expand-file-name (emms-track-name track))) - -(defun emms-player-xmms2--playlist-tracks () - "Playable tracks of the current EMMS playlist, in order." - (with-current-emms-playlist - (cl-remove-if-not - #'emms-player-xmms2-playable-p - (save-excursion - (nreverse (emms-playlist-tracks-in-region (point-min) (point-max))))))) - -(defun emms-player-xmms2--select (track) - "Move the EMMS selection to TRACK in the current playlist buffer." - (with-current-emms-playlist - (goto-char (point-min)) - (let (found) - (while (and (not found) (not (eobp))) - (if (eq (ignore-errors (emms-playlist-track-at (point))) track) - (setq found (point)) - (forward-line 1))) - (when found (emms-playlist-select found))))) - -(defun emms-player-xmms2--cancel-timer () - (when emms-player-xmms2--timer - (cancel-timer emms-player-xmms2--timer) - (setq emms-player-xmms2--timer nil))) - -;;; Following XMMS2 - -(defun emms-player-xmms2--advanced (pos) - "XMMS2 moved on to position POS by itself" - (setq emms-player-xmms2--pos pos) - (let ((track (nth (1- pos) emms-player-xmms2--tracks))) - (when track - (let ((emms-player-stopped-p t)) ; don't let EMMS pick the next track - (emms-player-stopped)) - (emms-player-xmms2--select track) - (emms-player-started 'emms-player-xmms2)))) - -(defun emms-player-xmms2--went-idle (pos) - "XMMS2 stopped without asking. POS is its marker position" - (emms-player-xmms2--cancel-timer) - (setq emms-player-xmms2--seen-playing nil) - (if (or (null pos) (>= pos (length emms-player-xmms2--tracks))) - (emms-player-stopped) - (let ((emms-player-stopped-p t)) - (emms-player-stopped)))) - -(defun emms-player-xmms2--poll () - (let ((state (emms-player-xmms2--state)) - (pos (car (emms-player-xmms2--list-info)))) - (cond ((member state '("Playing" "Paused")) - (setq emms-player-xmms2--seen-playing t) - (when (and pos (not (eql pos emms-player-xmms2--pos))) - (emms-player-xmms2--advanced pos))) - ((and emms-player-xmms2--seen-playing (equal state "Stopped")) - (emms-player-xmms2--went-idle pos))))) - -;;; EMMS API - -(defun emms-player-xmms2-playable-p (track) - "Return non-nil when can play TRACK." - (and (eq (emms-track-type track) 'file) - (string-match (emms-player-get emms-player-xmms2 'regex) - (emms-track-name track)) - (executable-find emms-player-xmms2-command) - t)) - -(defun emms-player-xmms2-start (track) - "Play TRACK, syncing XMMS2's playlist with EMMS's first if needed." - (emms-player-xmms2--cancel-timer) - (setq emms-player-xmms2--seen-playing nil) - (let* ((tracks (emms-player-xmms2--playlist-tracks)) - (index (cl-position track tracks :test #'eq))) - (unless index - (setq tracks (list track) index 0)) - (let* ((names (mapcar #'emms-player-xmms2--name tracks)) - (info (emms-player-xmms2--list-info))) - (unless (and (equal names emms-player-xmms2--synced) - info (= (cdr info) (length names))) - (emms-player-xmms2--run "clear") - (apply #'emms-player-xmms2--run "add" "-f" names) - (setq emms-player-xmms2--synced names)) - (setq emms-player-xmms2--tracks tracks - emms-player-xmms2--pos (1+ index)) - (if (and (emms-player-xmms2--run "jump" (number-to-string (1+ index))) - (emms-player-xmms2--run "play")) - (progn - (emms-player-started 'emms-player-xmms2) - (setq emms-player-xmms2--timer - (run-at-time emms-player-xmms2-check-interval - emms-player-xmms2-check-interval - #'emms-player-xmms2--poll))) - (message "XMMS2: could not start %s" (car names)))))) - -(defun emms-player-xmms2-stop () - "Stop playback." - (interactive) - (emms-player-xmms2--cancel-timer) - (setq emms-player-xmms2--seen-playing nil) - (emms-player-xmms2--run "stop") - (let ((emms-player-stopped-p t)) - (emms-player-stopped))) - -(defun emms-player-xmms2-pause () - "Pause playback." - (interactive) - (emms-player-xmms2--run "pause")) - -(defun emms-player-xmms2-resume () - "Resume playback." - (interactive) - (emms-player-xmms2--run "play")) - -(defun emms-player-xmms2-seek (amount) - "Seek by AMOUNT seconds." - (interactive "nSeconds: ") - (emms-player-xmms2--run "seek" (format "%+d" (round amount)))) - -(defun emms-player-xmms2-seek-to (pos) - "Seek to POS seconds from the start of the track." - (interactive "nSeconds: ") - (emms-player-xmms2--run "seek" (number-to-string (round pos)))) - -(defun emms-player-xmms2-resync () - "Force the next start to rebuild XMMS2's playlist from EMMS's." - (interactive) - (setq emms-player-xmms2--synced nil)) - -(provide 'emms-player-xmms2) - -;;; emms-player-xmms2.el ends here - -#+end_src - -#+RESULTS: -: emms-player-xmms2 - -** EMMS - for real now -EMMS, the Emacs MultiMedia System (but mostly its just used for music). -EMMS has a Doom Emacs module, so it doesnt require a ~(package!)~ line - -Here we 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 - (add-to-list 'load-path "/home/hi/.config/doom/") -(use-package! emms -:commands (emms emms-browser emms-player-mpd-update-all emms-cache-set-from-mpd-all emms emms-pause emms-next emms-previous emms-stop - emms-random emms-add-directory-tree emms-play-playlist) -#+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-browser - :desc "Emms" "e" #'emms - :desc "Play/pause" "SPC" #'emms-pause - :desc "Next" "n" #'emms-next - :desc "Previous" "p" #'emms-previous - :desc "Stop" "s" #'emms-stop - :desc "Add" "a" #'emms-add-playlist - :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 XMMS2 instead of MPRIS or Mpd. -#+begin_src emacs-lisp - -(require 'emms-player-xmms2) -(setq - emms-player-list '(emms-player-xmms2) - #+end_src - - Stop lyrics from scrolling, and have them appear on the minibuffer - #+begin_src emacs-lisp - emms-lyrics-scroll-p nil - emms-lyrics-display-on-minibuffer t - emms-lyrics-display-on-modeline nil - #+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/playlists/") - #+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 - -Turn on the little [ARTIST - ALBUM - TITLE] indicator in the modeline. -#+begin_src emacs-lisp -(emms-mode-line-mode 1) -#+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 - -* vc -#+begin_quote -Now you don't even need a terminal to do your version control! -#+end_quote -** 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 -** vc-jj -~vc-jj~ adds jujutsu integration to Emacs's ~vc~! -#+begin_src emacs-lisp :tangle ~/.config/doom/packages.el -(package! vc-jj) -#+END_SRC - -Then, we actually enable it. -#+begin_src emacs-lisp -(use-package! vc-jj) -#+end_src -vc-jj has a bit of a... weird flow, it runs ~jj commit~ instead of ~jj describe~, and doesnt advance bookmarks the way i usually do in my flow. - -Here we fix it! -#+begin_src emacs-lisp -(after! vc-jj - (defvar my/vc-jj-advance-to nil) - - (defun my/vc-jj-bookmark-advance (&optional names) - "Advance the closest bookmarks (or just NAMES) forward." - (interactive - (when current-prefix-arg - (list (completing-read-multiple - "Advance bookmarks: " - (vc-jj--process-lines - nil "bookmark" "list" - "-T" "if(!self.remote(), self.name() ++ '\n')"))))) - (with-temp-buffer - (let ((status (apply #'vc-jj--call nil t "bookmark" "advance" - (append (when my/vc-jj-advance-to - (list "--to" my/vc-jj-advance-to)) - names)))) - (message "vc-jj: %s" (string-trim (buffer-string))) - status))) - - (defun my/vc-jj--advance-before-push (&rest _) - (my/vc-jj-bookmark-advance)) - (advice-add 'vc-jj-push :before #'my/vc-jj--advance-before-push) - (setq my/vc-jj-advance-to "@-") - - (defun my/vc-jj-checkin (files comment &optional _rev) - "Describe @ and start a fresh change." - (let ((default-directory (vc-jj-root (car files)))) - (vc-jj-modify-change-comment nil "@" comment) - (vc-jj--command-dispatched nil 0 nil "new" "--quiet"))) - (advice-add 'vc-jj-checkin :override #'my/vc-jj-checkin)) -#+end_src -Now, this opens an ugly buffer in a split window and just... leaves it there. -A simple fix indeed. -#+begin_src emacs-lisp -(after! vc-jj - (add-to-list 'display-buffer-alist - '("\\`\\*vc-jj : " - (display-buffer-no-window) - (allow-no-window . t))) - - (defun my/vc-jj--report-push (&rest _) - (when-let* ((root (vc-jj-root default-directory)) - (buf (get-buffer (format "*vc-jj : %s*" (expand-file-name root)))) - (proc (get-buffer-process buf))) - (add-function - :around (process-sentinel proc) - (lambda (orig p event) - (unwind-protect (funcall orig p event) - (when (memq (process-status p) '(exit signal)) - (if (zerop (process-exit-status p)) - (message "vc-jj: push done") - (message "vc-jj: push FAILED, output below") - (let ((display-buffer-alist nil)) - (pop-to-buffer buf))))))))) - (defvar vc--inhibit-async-window) - - (defun my/vc-jj--push-no-window (orig &rest args) - (let ((vc--inhibit-async-window t)) - (apply orig args))) - - (advice-add 'vc-jj-push :around #'my/vc-jj--push-no-window) - (advice-add 'vc-jj-push :after #'my/vc-jj--report-push) - (define-advice ansi-color-filter-region (:around (fn &rest args) my/vc-jj-writable) - (let ((inhibit-read-only (or inhibit-read-only - (string-prefix-p "*vc-jj" (buffer-name))))) - (apply fn args)))) -#+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/") -(setq org-agenda-files "~/org/todo.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 :tangle ~/.config/doom/packages.el -(package! poly-org) -#+end_src -#+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. - -Here we unpin org-roam from Doom's version, as it is reccomended for custom configs like this. -#+begin_src emacs-lisp :tangle ~/.config/doom/packages.el -(unpin! org-roam) -#+end_src - -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. -#+begin_src emacs-lisp :tangle ~/.config/doom/packages.el -(package! org-roam-ui) -#+end_src - -Websocket required -#+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 :tangle ~/.config/doom/packages.el -(package! org-appear) -#+end_src - -#+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 :tangle ~/.config/doom/packages.el -(package! org-modern-indent - :recipe (:host github :repo "jdtsmith/org-modern-indent")) -#+end_src -#+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 :tangle ~/.config/doom/packages.el -(package! elpher) -#+end_src -#+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. - -** 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 ("d" . "dired") - :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 :tangle ~/.config/doom/packages.el -(package! eat) -#+end_src -#+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? -#+begin_src emacs-lisp :tangle ~/.config/doom/packages.el -(package! nov) -#+end_src - -#+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 - -** try -~try~ is a package that lets you ~try~ out other packages without fully installing them! -#+begin_src emacs-lisp :tangle ~/.config/doom/packages.el -(package! try) -#+end_src -That's about all ~try~ needs. -* 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 |
