Skip to content

Instantly share code, notes, and snippets.

@jclosure
Created July 7, 2026 20:49
Show Gist options
  • Select an option

  • Save jclosure/f90189e234bb40de68b506cd3a4f8972 to your computer and use it in GitHub Desktop.

Select an option

Save jclosure/f90189e234bb40de68b506cd3a4f8972 to your computer and use it in GitHub Desktop.
2026 - V1 Emacs config
;; V1
;;;;; EARLY SET
(menu-bar-mode -1)
(tool-bar-mode -1)
(scroll-bar-mode -1)
(blink-cursor-mode -1)
(setq inhibit-startup-screen t)
(global-hl-line-mode +1)
(line-number-mode +1)
(global-display-line-numbers-mode 1)
(column-number-mode t)
(size-indication-mode t)
;; Minimal garbage collection during user idle time to keep memory stable
(run-with-idle-timer 5 t #'garbage-collect)
;;;;;; IMMEDIATE LOAD
(require 'package)
(add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t)
(when (< emacs-major-version 29)
(add-to-list 'package-archives '("gnu" . "https://elpa.gnu.org/packages/")))
(package-initialize)
;;; Package management (use-package)
(unless (package-installed-p 'use-package)
(package-refresh-contents)
(package-install 'use-package))
(require 'use-package)
(setq use-package-always-ensure t) ; Ensure packages are always installed
;; Load theme immediately
(use-package modus-themes
:defer nil
:init (add-to-list 'custom-theme-load-path "~/.emacs.d/themes/")
:config (load-theme 'modus-vivendi t))
;;;; LATER SET
(global-auto-revert-mode t)
;; the value is in 1/10pt, so 100 will give you 10pt, etc.
(set-face-attribute 'default nil :height 140) ;; 14 font
(fset 'yes-or-no-p 'y-or-n-p)
(setq mode-line-position
'(;; %p print percent of buffer above top of window, o Top, Bot or All
;; (-3 "%p")
;; %I print the size of the buffer, with kmG etc
;; (size-indication-mode ("/" (-4 "%I")))
;; " "
;; %l print the current line number
;; %c print the current column
(line-number-mode ("%l" (column-number-mode ":%c")))))
(setq org-src-fontify-natively t)
;; disable the bell when switching frame
(setq ring-bell-function 'ignore)
;;; Backup settings
(setq backup-directory-alist
`(("." . ,(concat user-emacs-directory "backups"))))
(setq version-control t)
(setq kept-new-versions 2)
(setq kept-old-versions 2)
(setq delete-old-versions t)
(setq backup-by-copying t)
(setq vc-follow-symlinks nil)
;; Don't wrap lines
(setq-default truncate-lines t)
;;;;; DEFERRED LOAD
(use-package vertico
:defer t
:hook (after-init . vertico-mode))
(use-package orderless
:defer t
:after vertico
:init (setq completion-styles '(orderless basic)))
(use-package marginalia
:defer t
:hook (after-init . marginalia-mode))
(use-package no-littering
:defer t
:ensure t)
(use-package executable
:defer t
:ensure t
:hook
((after-save .
executable-make-buffer-file-executable-if-script-p)))
;; move where i mean
(use-package mwim
:defer t
:ensure t
:bind
("C-a" . mwim-beginning-of-code-or-line)
("C-e" . mwim-end-of-code-or-line))
(use-package ws-butler
:defer t
:ensure t
:hook (prog-mode . ws-butler-mode)
:diminish ws-butler-mode)
(use-package volatile-highlights
:defer t
:ensure t
:hook
(after-init . volatile-highlights-mode))
;; the scratch buffer will persist between runs
(use-package persistent-scratch
:ensure t
:defer t
;; This tells use-package to load the package
;; automatically after Emacs finishes initializing
:hook (after-init . persistent-scratch-setup-default)
:config
(progn
(setq scratch-buffers '("*scratch*" "*copy-log*"))
(persistent-scratch-autosave-mode)))
(use-package persp-mode
:defer t
:ensure t
;; :after (projectile) ; Ensure projectile is loaded first
;; :hook (after-init . persp-mode) ; Enable to make work by default
:config
(setq persp-save-dir (concat user-emacs-directory "perspectives/")) ; Custom perspective save directory
(make-directory persp-save-dir t)
(setq persp-state-management t)
(setq persp-auto-save-when-idle t)
;; Save every 2 min
(setq persp-auto-save-idle-time 120))
(use-package saveplace
:defer t
:ensure t
:hook (after-init . save-place-mode)
:config
(setq save-place t) ; Enable save-place-mode
(setq save-place-file (concat user-emacs-directory "places"))) ; Set the save file location
(use-package free-keys
:defer t
:ensure nil
:commands free-keys)
(use-package helpful
:defer t
:ensure t
:bind
(("C-h f" . helpful-callable)
("C-h v" . helpful-variable)
("C-h k" . helpful-key)
("C-c C-d" . helpful-at-point)
("C-h F" . helpful-function)
("C-h C" . helpful-command)))
(use-package winner
:defer t
:ensure nil ;; Built-in package, so no installation is needed
:hook (after-init . winner-mode) ;; Enable winner-mode after Emacs starts
:bind (("C-c <left>" . winner-undo) ;; Undo window layout changes
("C-c <right>" . winner-redo)) ;; Redo window layout changes
:custom
(winner-boring-buffers '("*Completions*" "*Compile-Log*" "*helm*" "*Help*"))
:config
(message "Winner mode is active!"))
(use-package compile
:ensure nil
:defer t
:config
;; Ensure the compilation window appears on the right
(setq display-buffer-alist
'(("\\*compilation\\*"
(display-buffer-in-side-window)
(side . right) ;; Position the window on the right side
(window-width . 80) ;; Set the width of the window (adjust to your preference)
(reusable-frames . t)))) ;; Make sure it's reusable in the same frame
;; Automatically scroll the compilation window without giving it focus
(add-hook 'compilation-mode-hook
(lambda ()
(setq-local scroll-conservatively 101))) ;; This keeps scrolling smoothly
;; Optional: Make sure the output scrolls automatically
(setq compilation-scroll-output 'first-error) ;; or 'all to scroll all output
(setq compilation-window-height nil)) ;; Don't constrain the window height
;; Org-mode configuration
(use-package org
:defer t
:ensure t
:mode ("\\.org\\'" . org-mode)
:bind (("C-c l" . org-store-link)
("C-c a" . org-agenda)
("C-c c" . org-capture))
:config
;; Basic org-mode settings
(setq org-directory "~/org")
(setq org-default-notes-file (concat org-directory "/notes.org"))
;; Agenda files
(setq org-agenda-files (list org-directory))
;; Enable syntax highlighting in code blocks
(setq org-src-fontify-natively t)
(setq org-src-tab-acts-natively t)
;; Better code block editing
(setq org-edit-src-content-indentation 0)
(setq org-src-preserve-indentation t)
;; Log done items
(setq org-log-done 'time)
;; Todo keywords
(setq org-todo-keywords
'((sequence "TODO(t)" "IN-PROGRESS(i)" "WAITING(w)" "|" "DONE(d)" "CANCELLED(c)")))
;; Prettier bullets
(setq org-hide-leading-stars t))
;; Org-bullets for prettier heading bullets
(use-package org-bullets
:defer t
:ensure t
:hook (org-mode . org-bullets-mode))
;; Enable extended chars in terminal mode
;; Critical package allows System Copy with mouse in terminal
;; allows C-S-<char> in terminal
;; Install Kitty Keyboard Protocol (kkp) from MELPA if you haven't
(use-package kkp
:ensure t
:defer nil
:config
;; This enables the protocol for all terminal frames
(global-kkp-mode +1))
;; Multiple cursors
(use-package multiple-cursors
:ensure t
:defer nil
:bind (("C-S-c C-S-c" . mc/edit-lines) ;; Edit a region of lines simultaneously
("C->" . mc/mark-next-like-this) ;; Add a cursor to the next matching instance
("C-<" . mc/mark-previous-like-this) ;; Add a cursor to the previous matching instance
("C-c C-<" . mc/mark-all-like-this)) ;; Mark all matching instances in the buffer
:config
(progn
;; Optional: Customize settings after the package has loaded
(setq mc/insert-numbers-default 1)
;; Optional: Prevent <return> from exiting multiple-cursors-mode, allowing it to insert a newline (use C-g to exit instead)
;; (define-key mc/keymap (kbd "<return>") nil)
;; Don't ask to allow commands
(setq mc/always-run-for-all t)))
(use-package markdown-mode
:ensure t
:mode ("\\.md\\'" . markdown-mode)
:mode ("\\.markdown\\'" . markdown-mode)
:init
(setq markdown-fontify-code-blocks-natively t))
(use-package treesit-auto
:ensure t
:custom
(treesit-auto-install 'prompt) ; Asks for confirmation before downloading a new language grammar
:config
(treesit-auto-add-to-auto-mode-alist 'all)
(global-treesit-auto-mode))
(use-package swift-mode
:ensure t)
(use-package dired-x
:ensure nil ;; dired-x is built-in to Emacs
:after dired
:defer t
:bind (("C-x C-j" . dired-jump)
("C-x 4 C-j" . dired-jump-other-window))
:custom
;; 1. Define what files you want to hide (regex)
(dired-omit-files
(concat dired-omit-files "\\|^\\..*$\\|^__pycache__$|\\.pyc$"))
:config
(progn
;; 3. Enable Omit Mode automatically when Dired starts
(add-hook 'dired-mode-hook #'dired-omit-mode)
(setq-default dired-dwim-target t)
(setq dired-listing-switches "-alh")
(setq dired-mouse-drag-files t)))
;; -- File associations
;; --- File Modes ---
;; HEX
(use-package hexl-mode
:defer t
:ensure nil
:mode (("\\.bin\\'" . hexl-mode)
("\\.a\\'" . hexl-mode)
("\\.o\\'" . hexl-mode)
("\\.so\\'" . hexl-mode)
("\\.so.*\\'" . hexl-mode)
("\\.exe\\'" . hexl-mode)
("\\.dll\\'" . hexl-mode)))
;;;;;; PERSONAL BASE CONFIG
;; Terminal scrolling
(unless (display-graphic-p) ;; Only apply this in a terminal
(xterm-mouse-mode 1)
;; Bind standard vertical scroll events
(global-set-key (kbd "<mouse-4>") 'scroll-down-line)
(global-set-key (kbd "<mouse-5>") 'scroll-up-line))
(defun mark-buffer-unmodified-if-same-as-file ()
"Mark the current buffer as unmodified if its contents match the file on disk."
(interactive)
(when (and (buffer-file-name) ;; Ensure the buffer is associated with a file
(not (buffer-modified-p))) ;; Skip if already unmodified
(let ((buffer-contents (buffer-substring-no-properties (point-min) (point-max)))
(file-contents (with-temp-buffer
(insert-file-contents (buffer-file-name))
(buffer-substring-no-properties (point-min) (point-max)))))
(when (string= buffer-contents file-contents)
(set-buffer-modified-p nil)))))
;; Automatically check buffers when focus is lost
(add-hook 'focus-out-hook 'mark-buffer-unmodified-if-same-as-file)
;; (defun mark-buffers-unmodified-on-timer ()
;; "Iterate over file-backed buffers and mark them unmodified if their contents match the file."
;; (dolist (buf (buffer-list))
;; (with-current-buffer buf
;; (when (and (buffer-file-name buf) ;; Ensure buffer is file-backed
;; (buffer-modified-p)) ;; Skip unmodified buffers
;; (let ((buffer-contents (buffer-substring-no-properties (point-min) (point-max)))
;; (file-contents (with-temp-buffer
;; (insert-file-contents (buffer-file-name buf))
;; (buffer-substring-no-properties (point-min) (point-max)))))
;; (when (string= buffer-contents file-contents)
;; (set-buffer-modified-p nil)))))))
;; ;; Check buffers every 10 seconds, mark unmodified
;; (defvar buffer-cleanup-interval 10
;; "Interval in seconds for checking if buffers match their associated files.")
;; ;; Set up a timer to run the function periodically
;; (run-with-timer 0 buffer-cleanup-interval #'mark-buffers-unmodified-on-timer)
;;; backward delete instead of backward kill
(defun backward-delete-word (arg)
"Delete characters backward until encountering the beginning of a word.
With argument ARG, do this that many times."
(interactive "p")
(delete-region (point) (progn (backward-word arg) (point))))
(global-set-key (kbd "M-DEL") 'backward-delete-word)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment