Sam’s Emacs Config
;; This is to set the garbage collector to speedup the entire Emacs config startup time
;; and must go at the beginning of the config itself:
(setq gc-cons-threshold 100000000)
(add-hook 'after-init-hook (lambda () (setq gc-cons-threshold 800000)))
(use-package no-littering
:ensure t
:demand t)
;; Add font specific changes for personal machines
(when (member (system-name) '("notestation" "fossastation"))
(set-face-attribute 'default nil
:height (pcase (system-name)
("notestation" 125)
("fossastation" 125))))
;; Adding M1 Mac specific change to use 'gls' instead of 'ls' for dired sorting options:
;; From this related post since 'ls' based options for Dired don't work in MacOS natively:
;; https://github.com/d12frosted/homebrew-emacs-plus/issues/383
;; Aka, install 'coreutils' via brew, and then use the following:
(when (eq system-type 'darwin)
(setq insert-directory-program
(cond
((string-match "arm64" (shell-command-to-string "uname -m"))
"/opt/homebrew/bin/gls") ; For M1/M2 Macs
(t
"/usr/local/bin/gls")))) ; For Intel Macs
;; Add font specific changes for work Macbook to make it larger because default Mac font size sucks
(when (string= system-name "macboook-osm-sbanya")
(set-face-attribute 'default nil
:height (pcase (system-name)
("macboook-osm-sbanya" 140))))
;; Color Theme (Include Doom Themes And Related Packages)
;; Load color theme, and do 'org-restart' to make sure the theme loads correctly:
;; (load-theme 'wordperfect-plus-emacs)
;; (load-theme 'kojak-emacs)
;; (load-theme 'super-nintendo-emacs)
;; (load-theme 'morrowind)
;; (load-theme 'kirby-emacs)
;; (load-theme 'gruvbox-dark-hard)
;; (load-theme 'base16-bespin t)
;; (add-hook 'org-mode-hook (lambda () (load-theme 'morrowind t)))
;; Add 'gruvbox' themes from MELPA
(use-package gruvbox-theme
:ensure t)
;; Enable Doom Emacs themes:
;; Install and configure doom-themes as well as any other related packages:
(use-package doom-themes
:ensure t
:config
;; Global settings (defaults)
(setq doom-themes-enable-bold t ; if nil, bold is universally disabled
doom-themes-enable-italic t) ; if nil, italics is universally disabled
;; Load the doom-solarized-dark theme
(load-theme 'doom-solarized-dark-high-contrast t)
;; Enable flashing mode-line on errors
(doom-themes-visual-bell-config)
;; Enable custom neotree theme
(doom-themes-neotree-config)) ; all-the-icons fonts must be installed!
(use-package all-the-icons
:ensure t)
(use-package doom-modeline
:ensure t
:init (doom-modeline-mode 1))
(use-package neotree
:ensure t
:bind (("M-n" . neotree-toggle)))
(use-package nerd-icons
:ensure t
)
(use-package all-the-icons
:ensure t
:init
;; Install all-the-icons fonts if they are not already installed
(unless (member "all-the-icons" (font-family-list))
(all-the-icons-install-fonts t)))
;; Themes list to try out later:
;; https://melpa.org/#/doom-themes
;; NOTE:
;; In order to get the Doom Modeline to actually work with unicode charaters
;; I had to download the 'NerdFontsSymbolsOnly.zip', extract it,
;; and then install each of the .ttf files manually on MacOS:
;; https://github.com/ryanoasis/nerd-fonts/releases
(org-mode-restart)
;; Disable Default Tool Bar, Menu Bar, And Scroll Bar
;; Disable default GUI based UI to allow more focus on the editor itself:
(tool-bar-mode -1)
(menu-bar-mode -1)
(scroll-bar-mode -1)
;; Dashboard
(use-package dashboard
:ensure t
:config
(dashboard-setup-startup-hook)
(setq dashboard-banner-logo-title "Hello! Welcome to Emacs, have a fun time!"))
;; Rainbow-Mode
(use-package rainbow-mode
:ensure t
:hook prog-mode
:config
(rainbow-mode))
;; Beacon
(use-package beacon
:ensure t
:init
(beacon-mode 1))
;; Enable 'scroll-conservatively' to allow for sane scroll defaults at the bottom of a buffer instead of default jumping behavior
(setq scroll-conservatively 100)
;; Disable annoying default bell for warning messages:
(setq ring-bell-function 'ignore)
;; Which-Key
(use-package which-key
:defer 5
:ensure t
:config
(which-key-mode))
;; Avy: Use 'M-s' for 'avy-goto-word-0', and use 'M-l' for 'avy-goto-line'
(use-package avy
:ensure t
:bind
("M-s" . avy-goto-word-0)
("M-l" . avy-goto-line))
;; Add 'goto-line-preview' to replace default 'goto-line' Emacs function
(use-package goto-line-preview
:ensure t)
(global-set-key [remap goto-line] 'goto-line-preview)
;; Add 'visual-regexp' to easily view soon-to-be replaced text with 'vr/replace' and 'vr/query command
(use-package visual-regexp
:ensure t)
;; Show lines and columns on the modeline
(line-number-mode 1)
(column-number-mode 1)
;; Show clock in 24-hr format, and display date + time
(setq display-time-24hr-format t)
(setq display-time-day-and-date t)
(display-time-mode 1)
;; Change 'yes or no' prompt to just 'y or n':
(defalias 'yes-or-no-p 'y-or-n-p)
;; Add 'switch-window' to use 'C-o' plus Vim style keys to quickly switch buffers to the desired on-screen buffer
(use-package switch-window
:ensure t
:config
(setq switch-window-input-style 'minibuffer)
(setq switch-window-increase 4)
(setq switch-window-threshold 2)
(setq switch-window-shortcut-style 'qwerty)
(setq switch-window-querty-shortcuts
'("a" "s" "d" "f" "h" "j" "k" "l"))
:bind
([remap other-window] . switch-window))
;; Window Splitting Functions (Horizontal And Vertical)
(defun split-and-follow-horizontally ()
(interactive)
(split-window-below)
(balance-windows)
(other-window 1))
(global-set-key (kbd "C-x 2") 'split-and-follow-horizontally)
(defun split-and-follow-vertically ()
(interactive)
(split-window-right)
(balance-windows)
(other-window 1))
(global-set-key (kbd "C-x 3") 'split-and-follow-vertically)
;; Enable Subword-Mode so that you can go forward and backward between camel-case words
(global-subword-mode 1)
;; Enable Hungry-Delete to delete white-space character regions more easily
(use-package hungry-delete
:ensure t
:config (global-hungry-delete-mode))
;; Add visual wordwrap in every text mode
;; From this post:
;; https://www.reddit.com/r/emacs/comments/43vfl1/enable_wordwrap_in_orgmode/czl98d4/
(add-hook 'text-mode-hook 'turn-on-visual-line-mode)
;; Add 'vertico' for Helm-style autocompletion in mini-buffer
(use-package vertico
:ensure t
:init
(vertico-mode))
;; Adding 'helm' just so that I can use 'helm-occur' to replace 'helm-swoop' (since it doesn't expand buffers like Org Mode buffers) and 'Swiper' (which does not have configurable search colors for my theme)
;; Ensure helm-swoop is installed and configured
(use-package helm-swoop
:ensure t
:bind (("C-s" . helm-swoop))
:config
;; Use Helm Swoop for fuzzy finding in Dired
(with-eval-after-load 'dired
(define-key dired-mode-map (kbd "C-s") 'helm-swoop)))
;; Enable iBuffer Expert Mode To Instantly Killer Buffers With 'D'
(setq ibuffer-expert t)
(setq browse-url-browser-function 'eww-browse-url)
;; Force 'ediff' to open up vertically in new windows NOT frames
(advice-add 'ediff-window-display-p :override #'ignore) ; Open up ediff results in new windows not frames
(setq ediff-split-window-function 'split-window-vertically) ; Split the ediff results vertically
(use-package vterm
:ensure t)
;; Configure vterm so that you can open up different instances of it so that it automatically renames new instances accordingly:
;; This is to prevent myself from having to use 'tmux' in order to get the same effect:
(add-hook 'vterm-mode-hook 'rename-uniquely)
(use-package multi-vterm
:ensure t
:bind (("C-` v" . 'multi-vterm)
("C-` n" . 'multi-vterm-prev)
("C-` p" . 'multi-vterm-next)))
(use-package magit
:ensure t)
(use-package rainbow-delimiters
:ensure t
:hook (prog-mode . rainbow-delimiters-mode))
(setq-default tab-width 2)
(progn
(setq-default indent-tabs-mode nil)
)
;; Taken from here:
;; https://gist.github.com/Lukewh/2da7b54cd773f931b1bf710c84f2f0fb
(defun enable-minor-mode (my-pair)
"Enable minor mode if filename match the regexp. MY-PAIR is a cons cell (regexp . minor-mode)."
(if (buffer-file-name)
(if (string-match (car my-pair) buffer-file-name)
(funcall (cdr my-pair)))))
(use-package diminish
:ensure t
:init
(diminish 'hungry-delete-mode)
(diminish 'beacon-mode)
(diminish 'which-key-mode)
(diminish 'subword-mode)
(diminish 'rainbow-mode))
;; 'yasnippet' to utilize snippet templates with 'M-x yas-describe-tables'
;; (Note: Make sure your created snippets match mode's name, ex: '~/.emacs.d/snippets/python-mode')
(use-package yasnippet
:ensure t
:config
(use-package yasnippet-snippets
:ensure t)
;; Taken from this SO post:
;; https://stackoverflow.com/questions/46696009/adding-a-custom-yasnippet-directory-to-spacemacs
(setq yas-snippet-dirs (append yas-snippet-dirs '("~/.emacs.d/snippets")))
(yas-reload-all))
;; Add hook so that 'yasnippet' minor mode is enabled for certain modes (programming: 'C, C++, Python, JS', 'nXML', Org-Mode)
(add-hook 'c-mode-hook 'yas-minor-mode)
(add-hook 'c++-mode-hook 'yas-minor-mode)
(add-hook 'python-mode-hook 'yas-minor-mode)
(add-hook 'emacs-lisp-mode-hook 'yas-minor-mode)
(add-hook 'org-mode-hook 'yas-minor-mode)
(add-hook 'ruby-mode-hook 'yas-minor-mode)
(add-hook 'js-mode-hook 'yas-minor-mode)
(add-hook 'rjsx-mode-hook 'yas-minor-mode)
(add-hook 'typescript-mode-hook 'yas-minor-mode)
(add-hook 'web-mode-hook 'yas-minor-mode)
(add-hook 'csharp-mode-hook 'yas-minor-mode)
(add-hook 'vue-mode-hook 'yas-minor-mode)
;; Nuke Emacs 27.2's annoying issue of automatically expanding source blocks which ruins my Yasnippet override template
(setq org-src-tab-acts-natively nil)
;; Enable 'electric-pair-mode' to auto-complete / add parentheses whenever possible
(setq electric-pair-pairs '(
(?\( . ?\))
(?\[ . ?\])
(?\{ . ?\})
))
(electric-pair-mode t)
;; Disable pairing of '<' with '>' to avoid weird expansion issues in Org-Mode for Yasnippets:
(add-function :before-until electric-pair-inhibit-predicate
(lambda (c) (eq c ?<)))
(use-package lsp-mode
:ensure t
:commands lsp
:hook ((typescript-mode js2-mode rjsx-mode) . (lambda ()
(display-line-numbers-mode 1) ;; Enable line numbers
(lsp)))
:config
(setq lsp-prefer-flymake nil)) ;; Use Flycheck instead of Flymake
(use-package typescript-mode
:ensure t
:mode ("\\.tsx?\\'" . typescript-mode) ;; This will handle both .ts and .tsx
:hook (typescript-mode . (lambda () (display-line-numbers-mode 1))) ;; Enable line numbers
:config
(setq typescript-indent-level 2)) ;; Set indentation level for TypeScript
(use-package js2-mode
:ensure t
:mode ("\\.jsx?\\'" . js2-mode)
:hook (js2-mode . (lambda () (display-line-numbers-mode 1))) ;; Enable line numbers
:config
(setq js2-basic-offset 2) ;; Set indentation level for JavaScript
(setq js-indent-level 2) ;; Ensure proper indentation
(setq js-switch-indent-offset 2)) ;; Set switch indent level
(use-package rjsx-mode
:ensure t
:mode ("\\.jsx?\\'" . rjsx-mode) ;; Use rjsx-mode for better JSX support
:hook (rjsx-mode . (lambda () (display-line-numbers-mode 1))) ;; Enable line numbers
:config
(setq js-indent-level 2) ;; Ensure proper indentation
(setq js-switch-indent-offset 2)) ;; Set switch indent level
(use-package css-mode
:ensure t
:mode ("\\.css\\'" . css-mode)
:config
(setq css-indent-offset 2))
(use-package lsp-ui
:ensure t
:after lsp
:commands lsp-ui-mode)
(use-package company
:ensure t
:after lsp
:config
(setq company-minimum-prefix-length 1
company-idle-delay 0.0))
(use-package flycheck
:ensure t
:after lsp
:config
(setq flycheck-check-syntax-automatically '(save mode-enabled))
(global-flycheck-mode))
(use-package prettier-js
:ensure t
:hook ((typescript-mode js2-mode rjsx-mode) . prettier-js-mode)) ;; Enable Prettier for all relevant modes
(use-package highlight-indent-guides
:ensure t
:config
(setq highlight-indent-guides-method 'character)
(setq highlight-indent-guides-character ?\|)
(setq highlight-indent-guides-auto-odd-face-perc 0.2)
(setq highlight-indent-guides-auto-even-face-perc 0.2)
(add-hook 'prog-mode-hook 'highlight-indent-guides-mode)) ;; Enable for programming modes
(use-package indent-guide
:ensure t
:config
(setq indent-guide-char ?\|)
(setq indent-guide-delay 0)
(add-hook 'prog-mode-hook 'indent-guide-mode)) ;; Enable for programming modes
(use-package electric
:hook ((js2-mode rjsx-mode typescript-mode) . electric-layout-mode)) ;; Enable electric layout mode for better indentation handling
;; Intel Macbook specific change to swap command and option keys
(when (eq system-type 'darwin)
;; Swap Command and Option keys
(setq mac-option-modifier 'super)
(setq mac-command-modifier 'meta))
;; Add custom keybindings list to later display somehow:
;; Keybindings List
;; C-M-z - Enable 'evil' and 'evil-collection' for Vim keybindings
;; S-Return - Launch 'vterm'
;; C-x w - Launch 'ranger.el'
;; f12 - Toggle full screen for Macbook workaround
;; C-x b - Enable iBuffer to check available buffers
;; f2 - Enable zoom-based Hydra to zoom in and out of available Emacs buffer
;; C-c a - Enable 'Org-Agenda' to view agenda of tasks
;; M-s - Jump to a specific word in a buffer with the 'avy-goto-word-0' function
;; M-l - Jump to a specific line in a buffer with the 'avy-goto-line' function
;; M-y - View the copy and paste clipboard via 'popup-kill-ring' package
;; C-s - Search in a buffer with 'helm-swoop'
;; C-c q - Mark a section and edit all instances simultaneously where it appears next
;; <s tab> - Enable source code-based yasnippet template for Org Mode
;; <b tab> - Enable bash code-based yasnippet template for Org Mode
;; M-x free-keys - Show available keybindings for future customization
;; C-c e - Edit Emacs config at any time
;; C-c r - Reload Emacs config at any time
;; C-<up> - Scroll up
;; C-<down> - Scroll down
;; M-<up> - Scroll other window up
;; M-<down> - Scroll other window down
;; M-<left> - Scroll other window left
;; M-<right> - Scroll other window right
;; C-<left> - Scroll left
;; C-<right> - Scroll right
;; C-c k - Show this keybindings table
;; Add 'evil' and 'evil-collection' to switch to Vim keybindings for programming occassionally with 'C-M-z'
(use-package evil
:ensure t
:init
(setq evil-want-integration t)
(setq evil-want-keybinding nil)
;; Allow Vim style page-up and page-down functionality with 'C-u' and 'C-d':
(setq evil-want-C-u-scroll t))
(use-package evil-collection
:after evil
:ensure t
:config
(evil-collection-init))
(global-set-key (kbd "C-M-z") 'evil-mode)
;; Super+Return to launch 'vterm'
(global-set-key (kbd "<s-return>") 'vterm)
;; Add '<f12>' keybinding for 'toggle-frame-fullscreen' function for Macbook workaround
(global-set-key (kbd "<f12>") 'toggle-frame-fullscreen)
;; Use 'get-youtube-video-name' to grab YouTube video name from YouTube link provided by user and place into buffer, set to '<f6>'
(defun get-youtube-video-name ()
"Grab the video title of a YouTube video using youtube-dl, and place it into an Emacs buffer."
(interactive)
(insert
(shell-command-to-string
(concat "youtube-dl --get-filename -o '%(title)s' $1"
(shell-quote-argument
(read-string "Enter your YouTube link here: "))))))
(global-set-key (kbd "<f6>") 'get-youtube-video-name)
;; iBuffer Via 'C-x b'
(global-set-key (kbd "C-x b") 'ibuffer)
;; Install 'Counsel' Which Installs 'Ivy' That Allows You To Switch Buffers Using 'ivy-switch-buffer' With 'C-x C-b'
(use-package counsel
:ensure t)
(global-set-key (kbd "C-x C-b") 'ivy-switch-buffer)
;; Modifying this so that it doesn't autocomplete in ERC based IRC buffers:
(add-hook 'erc-chat-mode-hook
(lambda () (ivy-mode 1)))
;; 'C-c a' for Org-Agenda Keybinding
(global-set-key "\C-ca" 'org-agenda)
;; Add 'free-keys' to determine the free keybindings present currently available in Emacs
(use-package free-keys
:ensure t)
;; Make 'dired' less verbose aka use 'dired-hide-details-mode'
;; NOTE:
;; Idea Taken From 'Emacs Rocks Episode 16: Dired' But Implemented A Little Differently:
(add-hook 'dired-mode-hook
'dired-hide-details-mode)
;; Allow 'dired' to move files between panes just like 'Midnight Commander'
;; NOTE:
;; From 'Emacs Rocks Episode 16: Dired':
(setq dired-dwim-target t)
;; Make 'dired' sort by directories first
(setq dired-listing-switches "-al --group-directories-first")
;; Force 'dired' to automatically update instantly when files change to prevent having to hit 'g' all the time
;; Taken from here:
;; https://superuser.com/questions/566393/how-to-configure-dired-to-update-instantly-when-files-folders-change
(add-hook 'dired-mode-hook 'auto-revert-mode)
;; Create custom 'my-org-capture' function to force 'Org-Capture' to split vertically
(defun my-org-capture (&rest args)
(interactive)
(let ((split-window-preferred-function 'split-window-vertically))
(funcall 'org-capture)))
(global-set-key (kbd "C-c c") 'my-org-capture)
;; Nuke 'org-adapt-indentation' variable setting value introduced in Emacs 27.2 so lines aren't auto-indented after headlines
(setq org-adapt-indentation nil)
;; Nuke 'org-startup-folded' variable setting value introduced in Emacs 27.2 so org docs aren't automatically expanded
(setq org-startup-folded t)
;; Add time-tracking for Org-Mode todo item state changes to place into ':LOGBOOK:' drawer
(setq org-log-into-drawer "LOGBOOK")
;; Set 'org-agenda-files' variable so that Org-Mode sees all scheduled items in Org-Agenda
(setq org-agenda-files (append
(file-expand-wildcards "~/hub/notes_private/*.org")))
;; Allow Org-Mode to edit SRC blocks within the same window
(setq org-src-window-setup 'current-window)
;; Allow Org-Mode to use an emacs-lisp src block template
(add-to-list 'org-structure-template-alist
'("el" . "src emacs-lisp"))
;; Remove '#' priority from tasks when changing task states
;; From a wonderful person named Samuel Loury from the Emacs Org Mode mailing list --> props to their assistance on this:
(defun my/org-trigger-hook (change-plist)
(let* ((type (plist-get change-plist :type))
(pos (plist-get change-plist :position))
(from (substring-no-properties (or (plist-get change-plist :from) "")))
(to (substring-no-properties (or (plist-get change-plist :to) "")))
)
(when (and
(eq type 'todo-state-change)
(member to org-done-keywords)
(member from org-not-done-keywords)
)
(org-priority (string-to-char " ")))))
(add-hook #'org-trigger-hook
#'my/org-trigger-hook)
;; Destroy annoying 'bookmark-set-fringe-mark' which shows up as a weird orange mark in Org Mode
;; Related post on this behavior:
;; https://www.reddit.com/r/orgmode/comments/u156dd/strange_orange_marker_on_captured_tasks/
(setq-default bookmark-set-fringe-mark nil)
;; Add 'ox-hugo' so that I can export blog posts from Org mode to 'hugo'
(use-package ox-hugo
:ensure t
:after ox)
;; Nuke Org Mode's use of 'electric-indent' mode which annoyingly indents list items by default
;; Taken from here:
;; https://www.philnewton.net/blog/electric-indent-with-org-mode/
(add-hook 'org-mode-hook
(lambda () (electric-indent-local-mode -1)))
;; Add Latex to Emacs path to force Org Mode to properly export to PDF
(setenv "PATH" (concat "/Library/TeX/texbin:" (getenv "PATH")))
(setq exec-path (append '("/Library/TeX/texbin") exec-path))
;; Edit Config Function
(defun config-edit ()
(interactive)
(find-file "~/hub/SamsEmacs/configuration.org"))
(global-set-key (kbd "C-c e") 'config-edit)
;; Reload Config Function
(defun config-reload ()
(interactive)
(org-babel-load-file (expand-file-name "~/hub/SamsEmacs/configuration.org")))
(global-set-key (kbd "C-c r") 'config-reload)
;; Nuke Emacs' ability to make backups and autosaves since its annoying and too bloated
(setq make-backup-files nil)
(setq auto-save-default nil)
;; Remove trailing whitespace on save
(add-hook 'before-save-hook 'delete-trailing-whitespace)
;; Default to UTF-8 encoding
(set-default-coding-systems 'utf-8)
(set-language-environment "UTF-8")
(prefer-coding-system 'utf-8)
(set-terminal-coding-system 'utf-8)
;; Force Emacs to always follow symlinks by default
;; NOTE:
;; Taken from this StackOverflow post:
;; https://stackoverflow.com/questions/15390178/emacs-and-symbolic-links
(setq vc-follow-symlinks t)
;; Force Emacs to copy to Windows based clipboard via 'wl-copy' workaround for WSL2
;; Taken from here:
;; https://github.com/microsoft/wslg/issues/15
(when (and (getenv "WAYLAND_DISPLAY") (not (equal (getenv "GDK_BACKEND") "x11")))
(setq
interprogram-cut-function
(lambda (text)
;; strangest thing: gui-select-text leads to gui-set-selection 'CLIPBOARD
;; text -- if I eval that with some string, it mostly lands on the wayland
;; clipboard, but not when it's invoked from this context.
;; (gui-set-selection 'CLIPBOARD text)
;; without the charset=utf-8 in type, emacs / wl-copy will crash when you paste emojis into a windows app
(start-process "wl-copy" nil "wl-copy" "--trim-newline" "--type" "text/plain;charset=utf-8" text))))