#+TITLE: Emacs Configuration #+AUTHOR: Thanos Apollo #+PROPERTY: header-args :tangle ~/.emacs.d/init.el :mkdirp yes #+auto_tangle: t #+STARTUP: overview * Fix for 29 #+begin_src emacs-lisp (add-to-list 'load-path "/usr/share/emacs/site-lisp/elpa/mu4e-1.8.14") #+end_src * System Information Set my name and email address #+begin_src emacs-lisp (setq user-full-name "Thanos Apollo" user-mail-address "public@thanosapollo.com") #+end_src Check the ~$HOSTNAME~ to set a variable for different devices #+begin_src emacs-lisp (defvar is-zeus (equal (system-name) "zeus")) (defvar is-hermes (equal (system-name) "hermes")) (defvar is-phone (equal (system-name) "localhost")) #+end_src Setup default browser as ~firefox~ #+begin_src emacs-lisp (setq browse-url-browser-function 'browse-url-generic browse-url-generic-program "firefox") #+end_src Set backup fails at ~~/Trash~ #+begin_src emacs-lisp (setq backup-directory-alist '((".*" . "~/.Trash"))) #+end_src Define essential keybindings #+begin_src emacs-lisp (define-prefix-command 'thanos/applications-map) (global-set-key (kbd "C-c a") 'thanos/applications-map) (define-prefix-command 'Create) (define-key thanos/applications-map (kbd "C-c") 'Create) (global-set-key (kbd "") 'keyboard-escape-quit) #+end_src * Setting Up Packages ** List of required packages Request the following packages: #+begin_src emacs-lisp (defvar thanos/packages '(emms tree-sitter org-snooze org-drill all-the-icons all-the-icons-dired all-the-icons-ivy-rich dap-mode toc-org emojify doom-themes doom-modeline gruvbox-theme counsel vterm multi-vterm which-key ivy ivy-rich helpful password-store org org-modern org-roam visual-fill-column rainbow-delimiters flycheck lsp-mode lsp-ui json-mode rjsx-mode typescript-mode python-mode pyvenv company company-box magit elfeed elfeed-goodies paredit corfu monkeytype sudo-edit consult alsamixer simple-httpd eshell-syntax-highlighting org-superstar pdf-tools org-auto-tangle sly org-download eshell-git-prompt eshell-vterm hackernews circe gptel beacon ement mu4e-alert pass eat)) #+end_src ** Installation & activation Set ~package-archives~, and install packages #+begin_src emacs-lisp (setq package-archives '(("melpa" . "https://melpa.org/packages/") ("elpa" . "https://elpa.gnu.org/packages/") ("nongnu" . "https://elpa.nongnu.org/nongnu/"))) ;; Activate all the packages (package-initialize) ;; Fetch the list of packages available (package-refresh-contents) ;; Install the missing packages (cl-mapcar (lambda (package) (unless (package-installed-p package) (package-install package))) thanos/packages) ;; Set and load custom.el (setq custom-file (concat user-emacs-directory "custom.el")) (load custom-file 'noerror) #+end_src * UI Settings ** Basic UI Fonts and basic appearance settings for each device #+begin_src emacs-lisp (setq inhibit-startup-message t) (setq initial-scratch-message nil) ;; Transparency (set-frame-parameter (selected-frame) 'alpha '(90 95)) (add-to-list 'default-frame-alist '(alpha 90 90)) (add-hook 'dired-mode-hook 'all-the-icons-dired-mode) (when (equal is-phone nil) (scroll-bar-mode -1) (set-fringe-mode 10)) (beacon-mode 1) (tool-bar-mode -1) (tooltip-mode -1) (menu-bar-mode -1) (which-key-mode 1) (blink-cursor-mode -1) (menu-bar--visual-line-mode-enable) (global-visual-line-mode 1) ;; Set emojis for emacs 29 (require 'emojify) (if (version< emacs-version "29") (setq global-emojify-mode 1) (setq global-emojify-mode 0)) (setq visible-bell t) (column-number-mode) (global-display-line-numbers-mode 1) (menu-bar--display-line-numbers-mode-relative) ;;Disable line numbers for some modes (dolist (mode '(pdf-view-mode-hook org-mode-hook term-mode-hook shell-mode-hook eshell-mode-hook vterm-mode-hook elfeed vterm-mode)) (add-hook mode (lambda () (display-line-numbers-mode 0)))) ;; Set font-size for each device (custom-set-faces (if is-hermes '(default ((t (:inherit nil :height 120 :family "Jetbrains Mono")))) '(default ((t (:inherit nil :height 135 :family "Jetbrains Mono")))))) #+end_src ** Theme #+begin_src emacs-lisp (load-theme 'doom-old-hope) (doom-modeline-mode 1) (setq doom-modeline-height 35) ;; Don't display battery-mode on desktop (if is-zeus (display-battery-mode 0) (display-battery-mode 1)) #+end_src ** Ivy #+begin_src emacs-lisp (require 'ivy) (ivy-mode 1) ;(setq ivy-use-virtual-buffers t) ;(setq enable-recursive-minibuffers t) (global-set-key (kbd "C-s") 'swiper) (define-key ivy-minibuffer-map (kbd "TAB") 'ivy-alt-done) (global-set-key "\C-s" 'swiper) (global-set-key (kbd "C-c C-r") 'ivy-resume) (global-set-key (kbd "") 'ivy-resume) (global-set-key (kbd "M-x") 'counsel-M-x) (global-set-key (kbd "C-x C-f") 'counsel-find-file) (global-set-key (kbd " f") 'counsel-describe-function) (global-set-key (kbd " v") 'counsel-describe-variable) (global-set-key (kbd " o") 'counsel-describe-symbol) (global-set-key (kbd " l") 'counsel-find-library) (global-set-key (kbd " i") 'counsel-info-lookup-symbol) (global-set-key (kbd " u") 'counsel-unicode-char) (global-set-key (kbd "C-c g") 'counsel-git) (global-set-key (kbd "C-c j") 'counsel-git-grep) (global-set-key (kbd "C-c k") 'counsel-ag) (global-set-key (kbd "C-x l") 'counsel-locate) (global-set-key (kbd "C-S-o") 'counsel-rhythmbox) (define-key minibuffer-local-map (kbd "C-r") 'counsel-minibuffer-history) (ivy-rich-mode 1) (all-the-icons-ivy-rich-mode 1) (setq ivy-use-selectable-prompt t) (global-set-key (kbd "C-c m") 'consult-imenu) (define-key thanos/applications-map (kbd "t") 'counsel-load-theme) #+end_src ** Helpful #+begin_src emacs-lisp (require 'helpful) (global-set-key (kbd "C-h f") #'helpful-callable) (global-set-key (kbd "C-h v") #'helpful-variable) (global-set-key (kbd "C-h k") #'helpful-key) (global-set-key (kbd "C-h x") #'helpful-command) (global-set-key (kbd "C-c C-d") #'helpful-at-point) (global-set-key (kbd "C-h F") #'helpful-function) (setq counsel-describe-function-function #'helpful-callable) (setq counsel-describe-variable-function #'helpful-variable) #+end_src * Navigation #+begin_src emacs-lisp (global-set-key (kbd "C-x r d") 'bookmark-delete) (global-set-key (kbd "C-x r C-r") 'bookmark-rename) #+end_src * Pass ** Setup Generate a random password between 20 and 40 characters #+begin_src emacs-lisp (setq password-store-password-length (+ 20 (random 20))) #+end_src ** Pass Launcher #+begin_src emacs-lisp (require 'password-store) (defun thanos/pass-launcher () "Launch Emacs as a front-end for pass." (interactive) (cl-flet ((pass-autotype (entry) (let ((user (password-store-get-field entry "user")) (pass (password-store-get entry))) (start-process-shell-command "xdotool" nil (if user (format "sleep 0.3 && xdotool getactivewindow type '%s' && xdotool getactivewindow key Tab && xdotool getactivewindow type '%s'" user pass) (format "sleep 0.3 && xdotool getactivewindow type 'thanosapollo' && xdotool getactivewindow key Tab && xdotool getactivewindow type '%s'" pass)))))) (let ((ivy-height 100)) (unwind-protect (with-selected-frame (make-frame '((name . "thanos/pass-launcher") (minibuffer . only) (fullscreen . 0) (undecorated . t) (internal-border-width . 10) (width . 80) (height . 11))) (let* ((choice (completing-read "Choose an action: " '("AUTO" "COPY" "EDIT" "GENERATE"))) (action (pcase choice ("AUTO" #'pass-autotype) ("COPY" #'password-store-copy) ("EDIT" #'password-store-edit) ("GENERATE" #'password-store-generate)))) (funcall action (ivy-read "Search: " (password-store-list))) (delete-frame))))))) #+end_src ** Keybindings #+begin_src emacs-lisp (define-prefix-command 'thanos/pass) (global-set-key (kbd "C-c p") 'thanos/pass) (define-key thanos/pass (kbd "i") 'password-store-insert) (define-key thanos/pass (kbd "e") 'password-store-edit) (define-key thanos/pass (kbd "g") 'password-store-generate) (define-key thanos/pass (kbd "s") 'smtp-get-pass) #+end_src * App Launcher #+begin_src emacs-lisp (defun thanos/app-launcher () "Launch Emacs as an Application Launcher." (interactive) (let* ((ivy-height 100)) (unwind-protect (with-selected-frame (make-frame '((name . "thanos/emacs-launcher") (minibuffer . only) (fullscreen . 0) (undecorated . t) (internal-border-width . 10) (width . 80) (height . 11))) (if is-zeus (progn (load-file "~/Developer/emacs-projects/emacs-app-launcher/app-launcher.el") (app-launcher-run-app)) (counsel-linux-app)) (delete-frame))))) #+end_src * VM Manager #+begin_src emacs-lisp (defvar vm-directory "~/VirtualMachines/") (defun vm-create-image () "Create qcow2 image." (interactive) (let ((name (format "%s%s.qcow2" vm-directory (read-string "Name: "))) (size (format "%s" (read-string "Size(G): ")))) (shell-command (format "qemu-img create -f qcow2 %s %sG" name size)))) (defun vm-run () "Spawn Virtual Machine." (interactive) (let ((memory (format "%sG" (read-string "Memory(G): "))) (cores (read-string "Cores: ")) (image (read-file-name "Image: " vm-directory)) (iso (if (y-or-n-p "Load iso?? ") (read-file-name "ISO: ") nil))) (async-shell-command (format "qemu-system-x86_64 -enable-kvm -m %s -smp %s -hda %s -vga qxl -device virtio-serial-pci -spice port=5930,disable-ticketing=on -display spice-app %s " memory cores image (if iso (concat "-cdrom " iso) ""))))) #+end_src * Dired ** Functions #+begin_src emacs-lisp (defun dired-watch-video () (interactive) (async-shell-command (format "mpv \"%s\"" (dired-get-filename)))) #+end_src ** Keybindings #+begin_src emacs-lisp (require 'dired) (define-key dired-mode-map "b" 'dired-up-directory) (define-key dired-mode-map "v" 'dired-watch-video) (define-key dired-mode-map "z" 'wdired-change-to-wdired-mode) #+end_src ** All-the-icons #+begin_src emacs-lisp (add-hook 'dired-mode-hook 'all-the-icons-dired-mode) (setq all-the-icons-dired-monochrome 'nil all-the-icons-dired-v-adjust 0.10) #+end_src * Org ** Org-Roam #+begin_src emacs-lisp ;; Create ~/Notes, ignore errors if it's already made (ignore-errors (make-directory "~/Notes")) (setq org-roam-directory "~/Notes" org-roam-dailies-directory "journal/") (org-roam-db-autosync-enable) (setq org-roam-node-display-template (concat "${title:50} "(propertize "${tags:30}" 'face 'org-tag))) (setq org-roam-db-node-include-function (lambda () (not (or (member "journal" (org-get-tags)) (member "memorize" (org-get-tags)))))) #+end_src *** Keybindings #+begin_src emacs-lisp ;; Set maps (define-prefix-command 'thanos/notes) (global-set-key (kbd "C-c n") 'thanos/notes) ;; org-roam keys (define-key thanos/notes (kbd "t") 'org-roam-buffer-toggle) (define-key thanos/notes (kbd "f") 'org-roam-node-find) (define-key thanos/notes (kbd "i") 'org-roam-node-insert) ;; Journaling (define-prefix-command 'Journal) (define-key thanos/notes (kbd "C-j") 'Journal) (define-key Journal (kbd "d") 'Journaling/dailies) (define-key Journal (kbd "C-c") 'org-roam-dailies-capture-today) (define-key Journal (kbd "C-t") 'org-roam-dailies-capture-tomorrow) (define-key Journal (kbd "C-y") 'org-roam-dailies-capture-yesterday) (define-key Journal (kbd "c") 'org-roam-dailies-goto-today) (define-key Journal (kbd "t") 'org-roam-dailies-goto-tomorrow) (define-key Journal (kbd "y") 'org-roam-dailies-goto-yesterday) (define-key org-mode-map (kbd "C-c C-.") 'org-roam-tag-add) (define-key org-mode-map (kbd "C-c i") 'org-id-get-create) #+end_src *** Templates #+begin_src emacs-lisp (setq org-roam-capture-templates '(("d" "default" plain "%?" :if-new (file+head "%<%Y%m%d%H%M%S>-${slug}.org" "#+title: ${title}\n") :unnarrowed t) ("l" "programming language" plain "* Characteristics\n\n- Family: %?\n- Inspired by: \n\n* Reference:\n\n" :if-new (file+head "%<%Y%m%d%H%M%S>-${slug}.org" "#+title: ${title}\n") :unnarrowed t) ("p" "MUS" plain "* Goals\n\n%?\n\n* Tasks\n\n** TODO Add initial tasks\n\n* Dates\n\n" :if-new (file+head "%<%Y%m%d%H%M%S>-${slug}.org" "#+title: ${title}\n#+filetags: MUS") :unnarrowed t))) ;; Dailies (setq org-roam-dailies-capture-templates '(("d" "default" entry "* %?" :target (file+head "%<%Y-%m-%d>.org" "#+title: %<%Y-%m-%d>\n")) ("j" "Daily Journaling" entry (file "~/org/Templates/journaling.org") :target (file+head "%<%Y-%m-%d>.org" "#+title: %<%Y-%m-%d>\n")) ("i" "Improve" entry (file "~/org/Templates/improve.org") :target (file+head "%<%Y-%m-%d>.org" "#+title: %<%Y-%m-%d>\n")))) #+end_src ** Themes *** Dracula #+begin_src emacs-lisp (defun thanos/org-theme-dracula () "Enable Dracula theme for Org headers." (interactive) (dolist (face '((org-level-1 1.7 "#8be9fd" extra-bold) (org-level-2 1.6 "#bd93f9" extra-bold) (org-level-3 1.5 "#50fa7b" bold) (org-level-4 1.4 "#ff79c6" semi-bold) (org-level-5 1.3 "#9aedfe" normal) (org-level-6 1.2 "#caa9fa" normal) (org-level-7 1.1 "#5af78e" normal) (org-level-8 1.0 "#ff92d0" normal))) (set-face-attribute (nth 0 face) nil :font "JetBrains Mono" :weight (nth 3 face) :height (nth 1 face) :foreground (nth 2 face))) (set-face-attribute 'org-table nil :font "JetBrains Mono" :weight 'normal :height 1.0 :foreground "#bfafdf")) #+end_src *** Darkone #+begin_src emacs-lisp (defun thanos/org-theme-darkone () "Enable Darkone theme for Org headers." (interactive) (dolist (face '((org-level-1 1.70 "#51afef" bold) (org-level-2 1.55 "#7FBCD2" bold) (org-level-3 1.40 "#da8548" bold) (org-level-4 1.20 "#da8548" semi-bold) (org-level-5 1.20 "#5699af" normal) (org-level-6 1.20 "#a9a1e1" normal) (org-level-7 1.10 "#46d9ff" normal) (org-level-8 1.00 "#ff6c6b" normal))) (set-face-attribute (nth 0 face) nil :font "Jetbrains Mono" :weight (nth 3 face) :height (nth 1 face) :foreground (nth 2 face))) (set-face-attribute 'org-table nil :font "Jetbrains Mono" :weight 'normal :height 1.0 :foreground "#A66CFF")) #+end_src *** Gruvbox #+begin_src emacs-lisp (defun thanos/org-theme-gruvbox () "Enable Darkone theme for Org headers." (interactive) (dolist (face '((org-level-1 1.70 "#fb4934" bold) (org-level-2 1.55 "#98971a" bold) (org-level-3 1.40 "#458588" bold) (org-level-4 1.20 "#b16286" semi-bold) (org-level-5 1.20 "#689d6a" normal) (org-level-6 1.20 "#d3869b" normal) (org-level-7 1.10 "#8ec07c" normal) (org-level-8 1.00 "#ebdbb2" normal))) (set-face-attribute (nth 0 face) nil :font "Jetbrains Mono" :weight (nth 3 face) :height (nth 1 face) :foreground (nth 2 face))) (set-face-attribute 'org-table nil :font "Jetbrains Mono" :weight 'normal :height 1.0 :foreground "#A66CFF")) #+end_src *** Org Modern #+begin_src emacs-lisp (modify-all-frames-parameters '((right-divider-width . 5) (internal-border-width . 5))) (dolist (face '(window-divider window-divider-first-pixel window-divider-last-pixel)) (face-spec-reset-face face) (set-face-foreground face (face-attribute 'default :background))) (set-face-background 'fringe (face-attribute 'default :background)) (setq ;; Edit settings org-auto-align-tags nil org-tags-column 0 org-catch-invisible-edits 'show-and-error org-special-ctrl-a/e t org-insert-heading-respect-content t ;; Org styling, hide markup etc. org-hide-emphasis-markers t org-pretty-entities t ;; Agenda styling org-agenda-tags-column 0 org-agenda-block-separator ?─ org-agenda-time-grid '((daily today require-timed) (800 1000 1200 1400 1600 1800 2000) " ┄┄┄┄┄ " "┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄") org-agenda-current-time-string "⭠ now ─────────────────────────────────────────────────") (global-org-modern-mode) (setq org-modern-todo nil) #+end_src ** Settings #+begin_src emacs-lisp (require 'ox-md nil t) (require 'org-download) (require 'org-drill) (setq org-directory "~/org/" org-agenda-files '("~/org/agenda.org") org-default-notes-file (expand-file-name "notes.org" org-directory) org-ellipsis " ▼ " org-log-done 'time org-hide-emphasis-markers nil ;;change to t to hide emphasis markers org-table-convert-region-max-lines 20000 org-agenda-start-log-mode t org-log-done 'time org-log-into-drawer t org-todo-keywords ;; This overwrites the default Doom org-todo-keywords '((sequence "TODO(t)" ;; A task that is ready to be tackled "BLOG(b)" ;; Blog writing assignments "GYM(g)" ;; Things to accomplish at the gym "WAIT(w)" ;; Something is holding up this task "|" ;; The pipe necessary to separate "active" states and "inactive" states "DONE(d)" ;; Task has been completed "CANCELLED(c)" )) org-superstar-headline-bullets-list '("◉" "●" "○" "●" "○" "●" "◆") org-superstar-itembullet-alist '((?+ . ?➤) (?- . ?✦))) ;; changes +/- symbols in item lists) #+end_src ~Keybindings:~ #+begin_src emacs-lisp (define-key org-mode-map (kbd "C-c t") 'org-time-stamp-inactive) (define-key org-mode-map (kbd "C-c s") 'org-download-screenshot) #+end_src ~Hooks~ #+begin_src emacs-lisp (add-hook 'org-mode-hook 'thanos/org-theme-gruvbox) (add-hook 'org-mode-hook 'flyspell-mode) (add-hook 'org-mode-hook 'toc-org-mode) #+end_src ** Babel #+begin_src emacs-lisp (defadvice org-edit-src-code (around set-buffer-file-name activate compile) (let ((file-name (buffer-file-name))) ;; (1) ad-do-it ;; (2) (setq buffer-file-name file-name))) ;; (3) (org-babel-do-load-languages 'org-babel-load-languages '((emacs-lisp . t) (python . t))) (setq org-structure-template-alist '(("e" . "src emacs-lisp") ("p" . "src python") ("l" . "src lisp") ("b" . "src bash") ("q" . "QUOTE"))) ;;Auto tangle (add-hook 'org-mode-hook 'org-auto-tangle-mode) #+end_src ** Org-download #+begin_src emacs-lisp (when (or (eq is-zeus t) (eq is-hermes t)) (setq org-download-screenshot-method "grim -g \"$(slurp)\" %s")) #+end_src * Memorize #+begin_src emacs-lisp (when is-zeus (load-file "~/Developer/emacs-projects/memorize/memorize.el")) #+end_src * Markdown ** Theme #+begin_src emacs-lisp (defun thanos/markdown-theme () (interactive) (dolist (face '(markdown-header-face-1 :height 2.0)))) #+end_src ** Settings #+begin_src emacs-lisp (require 'markdown-mode) (setq markdown-header-scaling t) (add-to-list 'auto-mode-alist '("\\.md\\'" . gfm-mode)) (setq markdown-command "multimarkdown") #+end_src * Programming ** Essentials #+begin_src emacs-lisp (electric-pair-mode 1) (auto-insert-mode 1) (global-flycheck-mode) (global-set-key (kbd "M-.") 'xref-find-definitions) (global-set-key (kbd "C-c l") 'display-line-numbers-mode) (require 'company) (add-hook 'after-init-hook 'global-company-mode) (define-key company-active-map (kbd "TAB") 'company-indent-or-complete-common) (setq company-idle-delay (lambda () (if (company-in-string-or-comment) nil 0.0))) (require 'company-box) (add-hook 'company-mode-hook 'company-box-mode) (require 'dap-mode) (dap-ui-mode) (setq indent-tabs-mode nil) #+end_src ** Magit #+begin_src emacs-lisp (require 'magit) (setq magit-display-buffer-function #'magit-display-buffer-same-window-except-diff-v1) (define-prefix-command 'thanos/magit) (global-set-key (kbd "C-c g") 'thanos/magit) (define-key thanos/magit (kbd "c") 'magit-clone) #+end_src ** Auto-insertions + Shell scripting/bash #+begin_src emacs-lisp (define-auto-insert '("\\.sh\\'" . "Bash skeleton") '("Description:" \n "#!/bin/bash")) (add-hook 'shell-script-mode #'auto-insert) #+end_src ** Emacs lisp #+begin_src emacs-lisp (setq tab-always-indent 'complete) (add-to-list 'completion-styles 'initials t) (add-hook 'emacs-lisp-mode-hook #'rainbow-delimiters-mode) (add-hook 'emacs-lisp-mode-hook #'company-mode) (add-hook 'emacs-lisp-mode-hook #'display-line-numbers-mode) #+end_src ** Common Lisp #+begin_src emacs-lisp (setq inferior-lisp-program "sbcl") (add-hook 'lisp-mode-hook #'rainbow-delimiters-mode) (add-hook 'lisp-mode-hook #'company-mode) (add-hook 'lisp-mode-hook #'display-line-numbers-mode) #+end_src ** LSP #+begin_src emacs-lisp (defun thanos/lsp-mode-setup () (setq lsp-headerline-breadcrumb-segments '(path-up-to-project file symbols)) (lsp-headerline-breadcrumb-mode)) (require 'lsp-mode) (add-hook 'lsp-mode #'thanos/lsp-mode-setup) (setq lsp-keymap-prefix "C-c l") (lsp-enable-which-key-integration t) (require 'lsp-ui) (add-hook 'lsp-mode 'lsp-ui-mode) (setq lsp-ui-doc-position 'bottom) #+end_src ** Python #+begin_src emacs-lisp ;; set pylsp with lsp-mode (setq lsp-pyls-server-command "~/.local/bin/pylsp") (require 'python-mode) (add-to-list 'auto-mode-alist '("\\.py\\'" . python-mode)) (add-hook 'python-mode 'lsp-deferred) #+end_src ** JSON #+begin_src emacs-lisp (require 'json-mode) (add-to-list 'auto-mode-alist '("\\.json'" . json-mode)) #+end_src * Elfeed ** Feeds #+begin_src emacs-lisp (require 'elfeed) (require 'elfeed-goodies) (setq elfeed-feeds '(("https://hackaday.com/blog/feed/" hackaday linux) ("https://protesilaos.com/news.xml" protesilaos) ("https://protesilaos.com/codelog.xml" proetesilaos) ("https://guix.gnu.org/feeds/blog.atom" gnu guix) ("https://thanosapollo.com/posts/index.xml" thanos) ("http://nullprogram.com/feed/" emacs linux) ("https://drewdevault.com/blog/index.xml" sourcehut drewdevault) ("https://spacepub.space/feeds/videos.xml?videoChannelId=2" drewdevault youtube) ("https://odysee.com/$/rss/@DistroTube:2" video dt) ("https://www.youtube.com/feeds/videos.xml?channel_id=UC7YOGHUfC1Tb6E4pudI9STA" video mental) ("https://www.youtube.com/feeds/videos.xml?channel_id=UCAiiOTio8Yu69c3XnR7nQBQ" video daviwil) ("https://videos.lukesmith.xyz/feeds/videos.atom?sort=-publishedAt&isLocal=true" video luke) ("https://www.youtube.com/feeds/videos.xml?channel_id=UCrc2iv2-G1FZ3VscM3zu2jg" video zoogirl) ("https://www.youtube.com/feeds/videos.xml?channel_id=UC0uTPqBCFIpZxlz_Lv1tk_g" video prot) ("https://www.youtube.com/feeds/videos.xml?channel_id=UCq6VFHwMzcMXbuKyG7SQYIg" video moist) ("https://www.youtube.com/feeds/videos.xml?channel_id=UC05XpvbHZUQOfA6xk4dlmcw" video djware) ("https://archlinux.org/feeds/news/" ArchLinux Latest) ("https://www.youtube.com/feeds/videos.xml?channel_id=UCsBjURrPoezykLs9EqgamOA" fireship video) ("https://www.youtube.com/feeds/videos.xml?channel_id=UCl-J-ovSJhA3or73Q2uVpow" medicosperf video) ("https://www.youtube.com/feeds/videos.xml?channel_id=UCSuHzQ3GrHSzoBbwrIq3LLA" naomi video) ("https://www.youtube.com/feeds/videos.xml?channel_id=UCqYPhGiB9tkShZorfgcL2lA" WhatIveLearned video) ("http://wikileaks.org/feed" wikileaks) ("https://hackernoon.com/feed" hackernoon) ("https://sachachua.com/blog/feed/" sacha emacs) ("https://www.youtube.com/feeds/videos.xml?channel_id=UCtMVHI3AJD4Qk4hcbZnI9ZQ" video OrdinaeryGamers) ("https://www.youtube.com/feeds/videos.xml?channel_id=UCl2mFZoRqjw_ELax4Yisf6w" video Louis) ("https://www.youtube.com/feeds/videos.xml?channel_id=UC1yNl2E66ZzKApQdRuTQ4tw " video sabine) ("https://bits.debian.org/feeds/feed.rss" debian linux) ("https://torrentfreak.com/feed" torrentfreak) ("https://www.youtube.com/feeds/videos.xml?channel_id=UCM6SlP9fiwPIjhkWmbg8Ojg" video liberated-programmer) ("https://odysee.com/$/rss/@seytonic:c" video seytonic) ("https://www.youtube.com/feeds/videos.xml?channel_id=UC1yNl2E66ZzKApQdRuTQ4tw" video sabine) ("https://wp.medscape.com/cx/rssfeeds/2700.xml" med medscape))) #+end_src ** Watch Videos Create function to watch videos using ~mpv~ #+begin_src emacs-lisp (defun elfeed-v-mpv (url) "Watch a video from URL in MPV" (async-shell-command (format "mpv \"%s\"" url))) (defun elfeed-view-mpv (&optional use-generic-p) "Youtube-feed link" (interactive "P") (let ((entries (elfeed-search-selected))) (cl-loop for entry in entries do (elfeed-untag entry 'unread) when (elfeed-entry-link entry) do (elfeed-v-mpv it)) (mapc #'elfeed-search-update-entry entries) (unless (use-region-p) (forward-line)))) #+end_src ** Settings & Keys #+begin_src emacs-lisp (define-key elfeed-search-mode-map (kbd "v") 'elfeed-view-mpv) (define-key elfeed-search-mode-map (kbd "U") 'elfeed-update) (define-key thanos/applications-map (kbd "f") 'elfeed) (setq elfeed-goodies/entry-pane-size 0.55) (elfeed-goodies/setup) #+end_src * PDF #+begin_src emacs-lisp (require 'pdf-tools) (pdf-tools-install) ;;Add pdf-isearch-minor-mode hook, otherwise isearch will be buggy ;;Darkmode hook, cause I don't want color or light in my life, I'm a vampire. (add-hook 'pdf-view-mode-hook 'pdf-isearch-minor-mode) (add-hook 'pdf-view-mode-hook 'pdf-view-midnight-minor-mode) (add-to-list 'auto-mode-alist '("\\.pdf\\'" . 'pdf-view-mode)) #+end_src * mu4e ** Setting up mail #+begin_src emacs-lisp (require 'smtpmail) (require 'mu4e) (when is-zeus (setq mu4e-update-interval (* 10 60))) (setq mu4e-get-mail-command "mbsync -a") (defun set-mu4e-context (context-name full-name mail-address signature) "Return a mu4e context named CONTEXT-NAME with :match-func matching folder name CONTEXT-NAME in Maildir. The context's `user-mail-address', `user-full-name' and `mu4e-compose-signature'`smtpmail-smpt-server' is set to MAIL-ADDRESS FULL-NAME SIGNATURE and SERVER respectively. Special folders are set to context specific folders." (let ((dir-name (concat "/" context-name))) (make-mu4e-context :name context-name ;; we match based on the maildir of the message :match-func `(lambda (msg) (when msg (string-match-p ,(concat "^" dir-name) (mu4e-message-field msg :maildir)))) :vars `((user-mail-address . ,mail-address) (user-full-name . ,full-name) (mu4e-sent-folder . ,(concat dir-name "/Sent")) (mu4e-drafts-folder . ,(concat dir-name "/Drafts")) (mu4e-trash-folder . ,(concat dir-name "/Trash")) (mu4e-trash-folder . ,(concat dir-name "/Starred")) (mu4e-refile-folder . ,(concat dir-name "/Archive")) (mu4e-compose-signature . ,signature))))) ;;Fixing duplicate UID errors when using mbsync and mu4e (setq mu4e-change-filenames-when-moving t) (setq mu4e-maildir-shortcuts '(("/Public/Inbox" . ?I) ("/Inbox" . ?i) ("/Sent" . ?s) ("/MUSofia/Inbox" . ?m) )) (setq mu4e-contexts (list (make-mu4e-context :name "Fastmail" :match-func (lambda (msg) (when msg (string-prefix-p "/" (mu4e-message-field msg :maildir)))) :vars '((user-mail-address . "thanosapollo@fastmail.com") (user-full-name . "Thanos Apollo") (mu4e-drafts-folder . "/Drafts") (mu4e-sent-folder . "/Sent") (mu4e-refile-folder . "/Archive") (mu4e-trash-folder . "/Trash"))) (make-mu4e-context :name "Public" :match-func (lambda (msg) (when msg (string-prefix-p "/" (mu4e-message-field msg :maildir)))) :vars '((user-mail-address . "public@thanosapollo.com") (user-full-name . "Thanos Apollo") (smtpmail-smtp-server . "smtp.fastmail.com") (smtpmail-smtp-user . "thanosapollo@fastmail.com") (smtpmail-smtp-service . 465) (mu4e-drafts-folder . "/Drafts") (mu4e-sent-folder . "/Sent") (mu4e-refile-folder . "/Archive") (mu4e-trash-folder . "/Trash"))))) (setq message-send-mail-function 'smtpmail-send-it smtpmail-smtp-server "smtp.fastmail.com" smtpmail-smtp-service 465 smtpmail-smtp-user "thanosapollo@fastmail.com" smtpmail-stream-type 'ssl mu4e-compose-signature "Thanos Apollo\nhttps://thanosapollo.com" mu4e-compose-context-policy 'ask mu4e-compose-format-flowed t) (setq mu4e-view-actions (delete-dups (append '(("gapply git patches" . mu4e-action-git-apply-patch) ("mgit am patch" . mu4e-action-git-apply-mbox) ("bb4 am patch" . mu4e-action-git-apply-b4) ("ssetup reword list with b4" . mu4e-action-setup-reword-b4) ("crun checkpatch script" . my-mu4e-action-run-check-patch) ("MCheck if merged" . my-mu4e-action-check-if-merged))))) #+end_src ** Actions #+begin_src emacs-lisp (setq mu4e-view-actions (delete-dups (append '(("gapply git patches" . mu4e-action-git-apply-patch) ("mgit am patch" . mu4e-action-git-apply-mbox) ("bb4 am patch" . mu4e-action-git-apply-b4) ("ssetup reword list with b4" . mu4e-action-setup-reword-b4) ("crun checkpatch script" . my-mu4e-action-run-check-patch) ("MCheck if merged" . my-mu4e-action-check-if-merged))))) #+end_src ** Notifications/Style #+begin_src emacs-lisp (require 'mu4e-alert) (mu4e-alert-enable-mode-line-display) (mu4e-alert-enable-notifications) #+end_src ** Keybindings #+begin_src emacs-lisp (define-key thanos/applications-map (kbd "m") 'mu4e) #+end_src * EMMS #+begin_src emacs-lisp (require 'emms) (emms-all) (setq emms-player-list '(emms-player-mpv) emms-player-mpv-parameters '("--no-video") emms-info-functions '(emms-info-native) emms-playlist-buffer-name "*Music*" emms-source-file-default-directory "~/Music/jazz") #+end_src ** Keybindings #+begin_src emacs-lisp (define-key 'thanos/applications-map (kbd "e") 'emms) (define-key emms-playlist-mode-map (kbd "A") 'emms-add-directory-tree) #+end_src * Eshell First let's set ~eshell-visual-commands~ + This are commands cannot be displayed properly with ~eshell~ #+begin_src emacs-lisp (setq eshell-visual-commands '("mocp" "htop" "nvim")) #+end_src ** Environment #+begin_src emacs-lisp (setenv "EDITOR" "emacsclient -c") (setenv "DEBEMAIL" "public@thanosapollo.com") (setenv "DEBNAME" "Thanos Apollo") #+end_src ** Completions #+begin_src emacs-lisp ;;;; sudo completion (defun pcomplete/sudo () "Completion rules for the `sudo' command." (let ((pcomplete-ignore-case t)) (pcomplete-here (funcall pcomplete-command-completion-function)) (while (pcomplete-here (pcomplete-entries))))) ;;;; systemctl completion (defcustom pcomplete-systemctl-commands '("disable" "enable" "status" "start" "restart" "stop" "reenable" "list-units" "list-unit-files") "p-completion candidates for `systemctl' main commands" :type '(repeat (string :tag "systemctl command")) :group 'pcomplete) (defvar pcomplete-systemd-units (split-string (shell-command-to-string "(systemctl list-units --all --full --no-legend;systemctl list-unit-files --full --no-legend)|while read -r a b; do echo \" $a\";done;")) "p-completion candidates for all `systemd' units") (defvar pcomplete-systemd-user-units (split-string (shell-command-to-string "(systemctl list-units --user --all --full --no-legend;systemctl list-unit-files --user --full --no-legend)|while read -r a b;do echo \" $a\";done;")) "p-completion candidates for all `systemd' user units") (defun pcomplete/systemctl () "Completion rules for the `systemctl' command." (pcomplete-here (append pcomplete-systemctl-commands '("--user"))) (cond ((pcomplete-test "--user") (pcomplete-here pcomplete-systemctl-commands) (pcomplete-here pcomplete-systemd-user-units)) (t (pcomplete-here pcomplete-systemd-units)))) ;;;; man completion (defvar pcomplete-man-user-commands (split-string (shell-command-to-string "apropos -s 1 .|while read -r a b; do echo \" $a\";done;")) "p-completion candidates for `man' command") (defun pcomplete/man () "Completion rules for the `man' command." (pcomplete-here pcomplete-man-user-commands)) ;; hut completion (defcustom pcomplete-hut-commands '("builds" "export" "git" "graphql" "lists" "help" "hg" "init" "meta" "pages" "paste" "todo") "p-completion candidates for `hut' main commands" :type '(repeat (string :tag "hut command")) :group 'pcomplete) (defun pcomplete/hut () "Completion rules for `hut' command" (pcomplete-here (append pcomplete-hut-commands))) #+end_src ** Aliases & Paths Set aliases for ~~/.emacs.d/eshell/alias~ similarly that I would for a ~~/.bashrc~ file #+begin_src fundamental :tangle ~/.emacs.d/eshell/alias alias ls ls -lah alias anki QTWEBENGINE_CHROMIUM_FLAGS="--disable-seccomp-filter-sandbox" anki alias b bluetoothctl alias ba bluetooth-autoconnect alias c pavucontrol alias ca config add alias cc config commit -m alias cpm config push -u origin master alias cs config status alias fanki flatpak run net.ankiweb.Anki alias ga git add alias gaa git add . alias gc git commit -m alias gp git push -u origin alias gpd git push -u origin developer alias gpm git push -u origin master alias grep grep --color=auto alias gs magit-status alias gl magit-log alias klight='brightnessctl --device \''tpacpi::kbd_backlight'\'' set 1 alias logout pkill -U $USER alias music mocp alias mykeys setxkbmap -option caps:escape alias r ranger alias sb sudo systemctl start bluetooth alias sweb BROWSER="firefox" yarn start alias vi nvim alias vim nvim alias weather curl wttr.in alias yeet paru -Rsc alias ytd yt-dlp #+end_src Set aliases for emacs functions and ~PATH~ #+begin_src emacs-lisp (defvar eshell-path-env (getenv "~/.local/bin")) (defalias 'o 'find-file) (defalias 'oo 'find-file-other-window) #+end_src ** Prompt #+begin_src emacs-lisp (eshell-git-prompt-use-theme 'multiline) (eshell-syntax-highlighting-global-mode 1) (setq eshell-highlight-prompt t) #+end_src ** Multi Eshell #+begin_src emacs-lisp (defun if-void (arg default) (if (boundp arg) (eval arg) default )) (defgroup multi-eshell nil "Simple support for having multiple shells open." :group 'languages) (defcustom multi-eshell-shell-function '(eshell) "Command called to create shell" :group 'multi-eshell) (defcustom multi-eshell-name "*eshell*" "The name of the buffer opened by the shell command." :type 'string :group 'multi-eshell) (defun multi-eshell-function () "This function opens the appropriate shell." (eval multi-eshell-shell-function) ) ;;;(defvar multi-eshell-function `(shell) ) ;;; Defines the shell. ('shell) or ('eshell) ;(defvar multi-eshell-name "*eshell*") ;;; Name of default shell or eshell buffer (defvar multi-eshell-ring (make-ring 100) "This stores a bunch of buffers, which are shells created by multi-eshell." ) (setq multi-eshell-index 0 ) (defvar multi-eshell-last-buffer nil) (defun multi-eshell-is-current-buffer-current-multi-eshell (&optional ignored) "Checks if current buffer is the current multi-eshell." (eq (current-buffer) (ring-ref multi-eshell-ring multi-eshell-index)) ) (defun multi-eshell-switch-to-current-shell (&optional ignored) "Switch to shell buffer." (if (buffer-live-p (ring-ref multi-eshell-ring multi-eshell-index)) (switch-to-buffer (ring-ref multi-eshell-ring multi-eshell-index)) ) ) (defun multi-eshell-current-shell (&optional ignored) "Returns the current multi-eshell." (ring-ref multi-eshell-ring multi-eshell-index) ) (defun multi-eshell-switch-to-next-live-shell (&optional ignored) "Switches to the next live shell. Creates one if none exists." (interactive "p") (let ((still-looking t) (empty nil)) (while (and still-looking (not empty)) (if (ring-empty-p multi-eshell-ring) (progn (setq empty t) (multi-eshell 1) ) (progn (if (buffer-live-p (ring-ref multi-eshell-ring multi-eshell-index)) (progn (setq multi-eshell-index (+ multi-eshell-index 1)) (switch-to-buffer (ring-ref multi-eshell-ring multi-eshell-index)) (setq still-looking nil) ) (ring-remove multi-eshell-ring multi-eshell-index) ) ) ) ) ) ) ;;;###autoload (defun multi-eshell-go-back (&optional ignored) "Switch to buffer multi-eshell-last-buffer." (interactive "p") (if (buffer-live-p multi-eshell-last-buffer) (switch-to-buffer multi-eshell-last-buffer) (message "Last buffer visited before multi-eshell is gone. Nothing to go back to..") )) ;;;###autoload (defun multi-eshell-switch (&optional ignored) "If current buffer is not an multi-eshell, switch to current multi-eshell buffer. Otherwise, switch to next multi-eshell buffer." (interactive "p") (progn (setq multi-eshell-last-buffer (current-buffer)) (let ((still-looking t) (empty nil)) (if (ring-empty-p multi-eshell-ring) (multi-eshell 1) (if (and (buffer-live-p (multi-eshell-current-shell) ) (not (eq (multi-eshell-current-shell) (current-buffer)))) (switch-to-buffer (multi-eshell-current-shell)) (multi-eshell-switch-to-next-live-shell) ) ) ))) ;;;###autoload (defun multi-eshell (&optional numshells) "Creates a shell buffer. If one already exists, this creates a new buffer, with the name '*shell*', where n is chosen by the function generate-new-buffer-name." (interactive "p") (progn (setq multi-eshell-last-buffer (current-buffer)) (dotimes (i (if-void 'numshells 1) nil) (let ( (tempname (generate-new-buffer-name "*tempshell*")) (new-buff-name (generate-new-buffer-name multi-eshell-name)) (localdir default-directory) ) (if (eq (get-buffer multi-eshell-name) nil) ;If a (progn (multi-eshell-function) ;(process-send-string (get-buffer-process new-buff-name) (concat "cd " localdir "\n")) (ring-insert multi-eshell-ring (current-buffer) ) (setq multi-eshell-index (+ multi-eshell-index 1)) ) (progn (interactive) (multi-eshell-function) (rename-buffer tempname) (multi-eshell-function) (rename-buffer new-buff-name ) (switch-to-buffer tempname) (rename-buffer multi-eshell-name) (switch-to-buffer new-buff-name) ;(process-send-string (get-buffer-process new-buff-name) (concat "cd " localdir "\n")) (ring-insert multi-eshell-ring (current-buffer) ) (setq multi-eshell-index (+ multi-eshell-index 1)) ) ) ) ) ) ) (defun shell-with-name (name) "Creates a shell with name given by the first argument, and switches to it. If a buffer with name already exists, we simply switch to it." (let ((buffer-of-name (get-buffer name)) (tempname (generate-new-buffer-name "*tempshell*") ) ) (cond ((bufferp buffer-of-name) ;If the buffer exists, switch to it (assume it is a shell) (switch-to-buffer name)) ( (bufferp (get-buffer multi-eshell-name)) (progn (multi-eshell-function) (rename-buffer tempname) (multi-eshell-function) (rename-buffer name) (switch-to-buffer tempname) (rename-buffer multi-eshell-name) (switch-to-buffer name))) ( t (progn (multi-eshell-function) (rename-buffer name)))))) #+end_src ** Keybindings #+begin_src emacs-lisp (define-prefix-command 'thanos/eshell-map) (global-set-key (kbd "C-c e") 'thanos/eshell-map) (define-key thanos/eshell-map (kbd "o") 'multi-eshell) (define-key thanos/eshell-map (kbd "n") 'multi-eshell-switch) #+end_src * Vterm #+begin_src emacs-lisp (defvar thanos/vterm-map (make-sparse-keymap)) (define-prefix-command 'thanos/vterm-map) (define-key global-map (kbd "C-c v") 'thanos/vterm-map) (define-key thanos/vterm-map (kbd "n") 'multi-vterm-next) (define-key thanos/vterm-map (kbd "p") 'multi-vterm-prev) (define-key thanos/vterm-map (kbd "d") 'multi-vterm-dedicated-open) (define-key thanos/vterm-map (kbd "o") 'multi-vterm) #+end_src * ERC #+begin_src emacs-lisp ;;; Code: (require 'erc) (defun erc-libera () (interactive) "Login to liberachat with erc." (erc-tls :server "irc.libera.chat" :port 6697 :nick "thanosapollo" :user "thanosapollo" :password (password-store-get "liberachat/thanos_apollo"))) #+end_src ** Keybindings #+begin_src emacs-lisp (define-key thanos/applications-map (kbd "i") 'erc-libera) #+end_src * Chatgpt #+begin_src emacs-lisp (require 'gptel) (define-key 'thanos/applications-map (kbd "c") 'gptel-send) (setq gptel-api-key (password-store-get "chatgpt/api")) #+end_src * YeeTube #+begin_src emacs-lisp (when is-zeus (load-file "~/Developer/emacs-projects/yeetube.el/yeetube.el")) (require 'yeetube) (setq yeetube-results-limit 15 yeetube-display-info-keys nil) (define-prefix-command 'thanos/yeetube) (global-set-key (kbd "C-c y") 'thanos/yeetube) (define-key thanos/yeetube (kbd "s") 'yeetube-search) (define-key thanos/yeetube (kbd "d") 'yeetube-download-videos) (define-key thanos/yeetube (kbd "p") 'yeetube-toggle-pause-mpv) (define-key yeetube-mode-map (kbd "c") 'yeetube-switch-mpv) #+end_src * Ement #+begin_src emacs-lisp (defun ement-login () (interactive) (ement-connect :user-id "@thanos_apollon:matrix.org" :password (password-store-get "matrix/thanos_apollon") :uri-prefix "https://matrix-client.matrix.org")) (define-key thanos/applications-map (kbd "M-e") 'ement-login) #+end_src * StumpWM #+begin_src emacs-lisp (setq stumpwm-shell-program "~/.stumpwm.d/modules/util/stumpish/stumpish") #+end_src * Misc ** Random functions #+begin_src emacs-lisp (defun thanos/center-buffer () "Centers/Uncenters selected buffer" (interactive) (if visual-fill-column-center-text (setq visual-fill-column-center-text nil) (setq visual-fill-column-center-text t)) (visual-fill-column-mode 1)) (defun thanos/rofi-switch-window () "Navigate X11 buffers using rofi." (interactive) (start-process-shell-command "rofi" nil "rofi -show window")) (defun thanos/run-in-background (command) "Run COMMAND in the background." (let ((command-parts (split-string command "[ ]+"))) (apply #'call-process `(,(car command-parts) nil 0 nil ,@(cdr command-parts))))) (defun rofi () "Run Rofi." (interactive) (thanos/run-in-background "rofi -show drun")) (defun thanos/volume-increase () "Increase Volume." (interactive) (start-process-shell-command "amixer" nil "amixer sset Master 5%+")) (defun thanos/volume-decrease () "Decrease Volume." (interactive) (start-process-shell-command "amixer" nil "amixer sset Master 5%-")) (defun thanos/restore-wallpaper () "Set NAME as wallpaper." (interactive) (start-process-shell-command "feh" nil "feh --bg-scale ~/dotfiles/wallpaper.png")) (defun thanos/emacs-keys () "Swap caps with ctrl." (interactive) (start-process-shell-command "setxkbmap" nil "setxkbmap us -option ctrl:swapcaps")) (defun thanos/greek-keyboard () "Swap caps with ctrl." (interactive) (start-process-shell-command "setxkbmap" nil "setxkbmap gr")) (defun thanos/exwm-update-class () (exwm-workspace-rename-buffer exwm-class-name)) (defun eshell-new() "Open a new instance of eshell." (interactive) (eshell 'N)) (defun make-mini-geiser () (interactive) (split-window-below 60) (geiser nil)) (defun start-polybar () "Check which system is running, start polybar accordingly." (interactive) (if (string= (system-name) "fsociety") (start-process-shell-command "polybar" nil "polybar main & polybar second") (start-process-shell-command "polybar" nil "polybar main"))) (defun create-text-scratch () "create a scratch buffer" (interactive) (switch-to-buffer (get-buffer-create "*Text Scratch*")) (org-mode)) (define-key Create (kbd "t") 'create-text-scratch) (defun create-scratch () (interactive) (switch-to-buffer (get-buffer-create "*scratch*")) (emacs-lisp-mode)) (defun thanos/frame () (let ((frame (make-frame '((minibuffer . only))))) (set-frame-height frame 300) (set-frame-width frame 800) (counsel-linux-app) frame)) (define-key Create (kbd "e") 'create-scratch) ;; #+end_src