#+PROPERTY: header-args :tangle "/home/yaqub/.emacs.d/init.el" * Initial Setup ** Niceties #+begin_src emacs-lisp (setq ring-bell-function 'ignore) (setq inhibit-startup-message t) (setq initial-buffer-choice t) #+end_src ** Backup to saves instead of leaving temporary files in . #+begin_src emacs-lisp (setq backup-directory-alist `(("." . "~/.saves"))) (setq backup-by-copying t) #+end_src ** Initialise use-package #+begin_src emacs-lisp (require 'package) (setq package-archives '(("melpa" . "https://melpa.org/packages/") ("org" . "https://orgmode.org/elpa/") ("gnu" . "https://elpa.gnu.org/packages/"))) (package-initialize) ;; Bootstrap use-package if not installed (unless (package-installed-p 'use-package) (package-refresh-contents) (package-install 'use-package)) ;; Ensure packages are installed automatically (setq use-package-always-ensure t) #+end_src * Appearance ** Fonts #+begin_src emacs-lisp ;; Set the default font for Latin, Greek, and Cyrillic (set-face-attribute 'default nil :family "SF Mono Terminal Regular" :height 160) ;; Adjust height as needed (set-face-attribute 'fixed-pitch nil :family (face-attribute 'default :family) :height (face-attribute 'default :height) :weight (face-attribute 'default :weight)) (set-face-attribute 'fixed-pitch-serif nil :family (face-attribute 'default :family) :height (face-attribute 'default :height) :weight (face-attribute 'default :weight)) ;; Set the font for CJK characters to Source Han Serif with double width (dolist (charset '(kana han cjk-misc bopomofo)) (set-fontset-font t charset (font-spec :family "Source Han Serif" :height 0.85) nil 'append)) ;; Fallback to Andale Mono for any Unicode characters not covered by the above (set-fontset-font t 'unicode (font-spec :family "Andale Mono") nil 'append) #+end_src ** Mac env. specific settings #+begin_src emacs-lisp (menu-bar-mode 1) (toggle-scroll-bar -1) (tool-bar-mode -1) (add-to-list 'default-frame-alist '(ns-transparent-titlebar . t)) (add-to-list 'default-frame-alist '(ns-appearance . dark)) #+end_src ** Theming and modeline #+begin_src emacs-lisp (use-package bliss-theme :ensure t :config (load-theme 'bliss t)) (use-package minions :ensure t :config (setq minions-mode-line-lighter "多") (setq minions-mode-line-delimiters '("" . "")) (minions-mode 1)) #+end_src * QoL Packages #+begin_src emacs-lisp (use-package bind-key :ensure t) (use-package olivetti :ensure t) (use-package vertico :ensure t :init (vertico-mode) (setq vertico-cycle t)) ;; Cycle through options like ivy ;; Vertico for better minibuffer completion (replaces ivy) (use-package vertico :ensure t :init (vertico-mode) (setq vertico-cycle t)) ;; Cycle through options like ivy ;; Marginalia for annotations (docstrings, keybindings, etc.) (use-package marginalia :ensure t :init (marginalia-mode)) ;; Consult for enhanced M-x, buffer switching, and more (replaces counsel) (use-package consult :ensure t :demand t :bind (("C-s" . consult-line) ;; Replaces swiper ("C-x b" . consult-buffer) ;; Replaces counsel-switch-buffer ("C-M-j" . consult-buffer) ;; Buffer switch (ivy-like behavior) :map minibuffer-local-map ("C-r" . consult-history))) ;; Replaces counsel-minibuffer-history ;; Orderless for fuzzy matching (replaces ivy's fuzzy searching) (use-package orderless :ensure t :init (setq completion-styles '(orderless basic) orderless-matching-styles '(orderless-literal orderless-regexp orderless-flex))) ;; Evil Mode (Vi-like keybindings) (use-package evil :ensure t :init (setq evil-want-integration t evil-want-keybinding nil) (evil-mode 1)) ;; Evil-collection for better integration with Emacs commands (use-package evil-collection :ensure t :after evil :config (evil-collection-init)) (use-package evil-org :ensure t :after org :hook (org-mode . (lambda () evil-org-mode)) :config (require 'evil-org-agenda) (evil-org-agenda-set-keys)) ;; Replace buffer switcher with consult-buffer in Evil ex-mode (evil-ex-define-cmd "b" 'consult-buffer) ;; Which-key for displaying available keybindings (use-package which-key :ensure t :init (which-key-mode)) ;; Persist minibuffer history (use-package savehist :ensure t :init (savehist-mode)) ;; Embark for acting on minibuffer selections (use-package embark :ensure t :bind (("C-." . embark-act) ;; Trigger actions on selected candidates ) :init (setq embark-prompter 'embark-keymap-prompter)) ;; Embark-consult for seamless integration (use-package embark-consult :ensure t :after (embark consult) :hook (embark-collect-mode . consult-preview-at-point-mode)) (add-hook 'prog-mode-hook 'display-line-numbers-mode) ;; Define a function to clean up whitespace in the buffer (defun yaqub/cleanup-buffer-whitespace () "Clean up whitespace in the buffer, including converting tabs to spaces." (interactive) (whitespace-cleanup)) ;; Define a function to set the key binding in programming modes (defun yaqub/set-cleanup-whitespace-key () (local-set-key (kbd "C-c w") 'yaqub/cleanup-buffer-whitespace)) ;; Add the key binding function to the prog-mode-hook (add-hook 'prog-mode-hook 'yaqub/set-cleanup-whitespace-key) #+end_src ** Modeline appearance #+begin_src emacs-lisp ;; Set all modeline text to orange (set-face-attribute 'mode-line nil :foreground "orange" :background (face-attribute 'mode-line :background) :weight 'normal) (set-face-attribute 'mode-line-inactive nil :foreground "orange" :background (face-attribute 'mode-line-inactive :background) :weight 'normal) ;; Set modeline buffer ID to Microgramma (set-face-attribute 'mode-line-buffer-id nil :family "MicrogrammaDMedExt" :weight 'normal) #+end_src #+RESULTS: ** Evil undo tree #+begin_src emacs-lisp (use-package undo-tree :ensure t :config (global-undo-tree-mode) (evil-set-undo-system 'undo-tree)) #+end_src * Coding ** Enable line numbers in prog-mode #+begin_src emacs-lisp (add-hook 'prog-mode-hook 'display-line-numbers-mode) #+end_src ** Enable whitespace cleanup in prog-mode #+begin_src emacs-lisp ;; Define a function to clean up whitespace in the buffer (defun yaqub/cleanup-buffer-whitespace () "Clean up whitespace in the buffer, including converting tabs to spaces." (interactive) (whitespace-cleanup)) ;; Define a function to set the key binding in programming modes (defun yaqub/set-cleanup-whitespace-key () (local-set-key (kbd "C-c w") 'yaqub/cleanup-buffer-whitespace)) ;; Add the key binding function to the prog-mode-hook (add-hook 'prog-mode-hook 'yaqub/set-cleanup-whitespace-key) #+end_src ** Setup Yasnippet Yasnippet is a template system for Emacs. #+begin_src emacs-lisp (use-package yasnippet :ensure t :init (yas-global-mode 1)) #+end_src ** Enable dired-sidebar #+begin_src emacs-lisp (use-package dired-sidebar :bind (("C-x C-n" . dired-sidebar-toggle-sidebar)) :ensure t :commands (dired-sidebar-toggle-sidebar) :init (add-hook 'dired-sidebar-mode-hook (lambda () (unless (file-remote-p default-directory) (auto-revert-mode)))) :config (push 'toggle-window-split dired-sidebar-toggle-hidden-commands) (push 'rotate-windows dired-sidebar-toggle-hidden-commands) (setq dired-sidebar-subtree-line-prefix "__") (setq dired-sidebar-theme 'vscode) (setq dired-sidebar-use-term-integration t) (setq dired-sidebar-use-custom-font t)) #+end_src ** Setup Company-mode Company mode is a text completion framework. #+begin_src emacs-lisp (use-package company :ensure t :init (global-company-mode)) #+end_src *** Setup Company-box Company-box is a frontend for company-mode, it provides a dropdown menu interface for completions. #+begin_src emacs-lisp (use-package company-box :ensure t :hook (company-mode . company-box-mode)) #+end_src ** Setup Editorconfig #+begin_src emacs-lisp (use-package editorconfig :ensure t :config (editorconfig-mode 1)) #+end_src ** Magit Magit is an interface to the version control system Git, implemented as an Emacs package. It aspires to be a complete Git porcelain. #+begin_src emacs-lisp (use-package magit :ensure t :bind (("C-x g" . magit-status))) #+end_src ** Auto-install treesit grammars #+begin_src emacs-lisp (use-package treesit-auto :ensure t :config (setq treesit-auto-install 'prompt) ; Automatically install grammars (global-treesit-auto-mode)) #+end_src ** Smart Parens #+begin_src emacs-lisp (use-package smartparens :ensure smartparens ;; install the package :hook (prog-mode text-mode markdown-mode) ;; add `smartparens-mode` to these hooks :config ;; load default config (require 'smartparens-config)) #+end_src * Writing ** Global bibliography variables #+begin_src emacs-lisp (setq yaqub/global-bibliography '("~/Zotero/References.bib") yaqub/global-library-path '("~/Zotero") yaqub/global-notes-path "~/Orgfiles/roam/") #+end_src ** Setup Org Here, we separate the org setup into its own function for clarity. #+begin_src emacs-lisp (use-package org :ensure t :custom (org-hide-emphasis-markers t) (org-startup-indented t) (org-startup-with-inline-images t) :config ;; Enable olivetti on all org buffers (add-hook 'org-mode-hook 'olivetti-mode) ;; add keybindings for org-mark-ring-goto at C-c C- and C-c C- (define-key org-mode-map (kbd "C-c ") 'org-mark-ring-goto) (define-key org-mode-map (kbd "C-c ") 'org-mark-ring-goto) ;; add keybindings for org-mark-ring-push at C-c C- and C-c C- (define-key org-mode-map (kbd "C-c ") 'org-mark-ring-push) (define-key org-mode-map (kbd "C-c ") 'org-mark-ring-push) ) #+end_src *** Org-roam Very important. #+begin_src emacs-lisp (use-package org-roam :ensure t :custom (org-roam-directory "~/Orgfiles/roam") :bind (("C-c n f" . org-roam-node-find) ("C-c n i" . org-roam-node-insert) ("C-c n g" . org-roam-graph) ("C-c n c" . org-roam-capture) ("C-c n d" . org-roam-dailies-goto-today) ("C-c n D" . org-roam-dailies-goto-date))) #+end_src *** Making sure org links open in the same window #+begin_src emacs-lisp (setq org-link-frame-setup '((file . find-file))) #+end_src When org-roam is enabled, make org-attach always attach to the /file/, not the /heading/. #+begin_src emacs-lisp (defun yaqub/org-attach-use-file-id () "Use the top-level :ID: property for attachments unless overridden by :ATTACH_INDIVIDUALLY:." (save-excursion (goto-char (point-min)) (let ((file-id (org-entry-get (point) "ID" t)) (attach-individual (org-entry-get (point-min) "ATTACH_INDIVIDUALLY"))) (if (and file-id (not attach-individual)) (setq-local org-attach-id-dir (concat (file-name-as-directory org-attach-directory) file-id)))))) (add-hook 'org-mode-hook 'yaqub/org-attach-use-file-id) (defun yaqub/org-attach-individually () "Add :ATTACH_INDIVIDUALLY: property to the current heading." (interactive) (org-set-property "ATTACH_INDIVIDUALLY" "t") (message ":ATTACH_INDIVIDUALLY: property added.")) (defun yaqub/org-attach-file-to-file-id () "Attach a file to the top-level ID if present, regardless of cursor position." (interactive) (save-excursion (goto-char (point-min)) (let ((file-id (org-entry-get (point) "ID" t))) (if file-id (setq-local org-attach-id-dir (concat (file-name-as-directory org-attach-directory) file-id))))) (save-excursion (goto-char (point-min)) (org-attach))) ;; Bind this to the usual attachment keybinding (C-c c-a) (with-eval-after-load 'org (define-key org-mode-map (kbd "C-c c-a") #'yaqub/org-attach-file-to-file-id)) #+end_src ** Setup LaTeX *** Set up AucTeX #+begin_src emacs-lisp (use-package auctex :ensure t :mode ("\\.tex\\'" . LaTeX-mode) :config (setq TeX-auto-save t) (setq TeX-parse-self t) (setq-default TeX-master nil) (add-hook 'LaTeX-mode-hook 'visual-line-mode) (add-hook 'LaTeX-mode-hook 'flyspell-mode) (add-hook 'LaTeX-mode-hook 'LaTeX-math-mode) (add-hook 'LaTeX-mode-hook 'turn-on-reftex) (setq reftex-plug-into-AUCTeX t) (setq TeX-PDF-mode t) ;; Use Biber with AUCTeX (setq TeX-command-BibTeX "Biber")) #+end_src * Reading ** Setup elfeed *** Elfeed #+begin_src emacs-lisp (use-package elfeed :ensure t) #+end_src *** TODO Elfeed Org *** TODO Elfeed Youtube * Anki Integration #+begin_src emacs-lisp (use-package anki-editor :ensure t :config (global-set-key (kbd "C-c a a") 'anki-editor-insert-note) (global-set-key (kbd "C-c a c") 'anki-editor-cloze-region) (global-set-key (kbd "C-c a p") 'anki-editor-push-notes)) #+end_src * Mentor Torrent Client #+begin_src emacs-lisp (use-package mentor :ensure t :after evil :config (setq mentor-rtorrent-external-rpc "~/.rtorrent-rpc.socket") (evil-set-initial-state 'mentor-mode 'emacs)) #+end_src * Minibuffer Shortcuts #+begin_src emacs-lisp ;; the command "eval-init" evaluates init.el (defun eval-init () (interactive) (load-file "~/.emacs.d/init.el")) ;; the command "home" opens home orgfile (defun home () (interactive) (find-file "/media/storage/Orgfiles/roam/home.org")) ;; the command "todo" opens todo orgfile (defun todo () (interactive) (find-file "/media/storage/Orgfiles/roam/todo.org")) ;; the command "yaqubmacs" opens dired at ~/Development/yaqubmacs (defun yaqubmacs () (interactive) (dired "/media/storage/Development/yaqubmacs")) #+END_SRC * Safe local vars Unsafe, but convenient #+begin_src emacs-lisp (setq enable-local-variables :all) #+end_src