diff --git a/emacs.d/.gitignore b/emacs.d/.gitignore new file mode 100644 index 0000000..ffb244f --- /dev/null +++ b/emacs.d/.gitignore @@ -0,0 +1,14 @@ +*~ +\#* +/elpa +/elpa-* +/history +/tree-sitter +/.cache +/eln-cache +/eshell +/transient + +/backup +/custom.el + diff --git a/emacs.d/dev.el b/emacs.d/dev.el new file mode 100644 index 0000000..9d1f85d --- /dev/null +++ b/emacs.d/dev.el @@ -0,0 +1,10 @@ +(use-package emacs + :ensure nil + :hook ((prog-mode . electric-pair-mode))) + +(use-package treesit-auto + :custom + (treesit-auto-install 'prompt) + :config + (treesit-auto-add-to-auto-mode-alist 'all) + (global-treesit-auto-mode)) diff --git a/emacs.d/dired.el b/emacs.d/dired.el new file mode 100644 index 0000000..a243d91 --- /dev/null +++ b/emacs.d/dired.el @@ -0,0 +1,40 @@ +(setq dired-kill-when-opening-new-dired-buffer t) + +(use-package dired + :ensure nil + :commands (dired) + :hook + ((dired-mode . dired-hide-details-mode) + (dired-mode . hl-line-mode) + (dired-mode . dired-omit-mode)) + :bind + ( :map dired-mode-map + ("." . dired-omit-mode)) + :config + (setq dired-omit-files "^\\.") + (setq dired-listing-switches "-AGFhlv --group-directories-first --time-style=long-iso") + (setq dired-recursive-copies 'always) + (setq dired-recursive-deletes 'always) + (setq delete-by-moving-to-trash t) + (setq dired-dwim-target t)) + +(use-package dired-subtree + :ensure t + :after dired + :bind + ( :map dired-mode-map + ("" . dired-subtree-toggle) + ("TAB" . dired-subtree-toggle) + ("" . dired-subtree-remove) + ("S-TAB" . dired-subtree-remove)) + :config + (setq dired-subtree-use-backgrounds nil)) + +(use-package trashed + :ensure t + :commands (trashed) + :config + (setq trashed-action-confirmer 'y-or-n-p) + (setq trashed-use-header-line t) + (setq trashed-sort-key '("Date deleted" . t)) + (setq trashed-date-format "%Y-%m-%d %H:%M:%S")) diff --git a/emacs.d/early-init.el b/emacs.d/early-init.el new file mode 100644 index 0000000..3bf45d0 --- /dev/null +++ b/emacs.d/early-init.el @@ -0,0 +1,23 @@ +(setq original-gc-cons-threshold gc-cons-threshold) +(setq gc-cons-threshold 10000000) + +(setq byte-compile-warnings '(not obsolete)) +(setq warning-suppress-log-types '((comp) (bytecomp))) +(setq native-comp-async-report-warnings-errors 'silent) + +(setq frame-inhibit-implied-resize t) +(setq inhibit-compacting-font-caches t) +(setq idle-update-delay 1.0) + +(setq initial-scratch-message nil) +(setq inhibit-startup-screen t) + +(menu-bar-mode 1) +(scroll-bar-mode 1) +(tool-bar-mode -1) + +(set-fringe-mode 10) + +;; TODO: figure out what these width/height numbers are exactly. they don't seem to be characters? +(setq default-frame-alist '((width . 165) + (height . 59))) diff --git a/emacs.d/editing.el b/emacs.d/editing.el new file mode 100644 index 0000000..63a0d27 --- /dev/null +++ b/emacs.d/editing.el @@ -0,0 +1,68 @@ +;; (use-package corfu +;; :ensure t +;; :hook (after-init . global-corfu-mode) +;; :bind (:map corfu-map ("" . corfu-complete)) +;; :config +;; (setq tab-always-indent 'complete) +;; (setq corfu-preview-current nil) +;; (setq corfu-min-width 20) + +;; (setq corfu-popupinfo-delay '(1.25 . 0.5)) +;; (corfu-popupinfo-mode 1) ; shows documentation after 'corfu-popupinfo-delay' + +;; ;; sort by input history +;; (with-eval-after-load 'savehist +;; (corfu-history-mode 1) +;; (add-to-list 'savehist-additional-variables 'corfu-history))) + +(setq-default tab-width 4) +(setq-default indent-tabs-mode t) + +(use-package corfu + :ensure t + :hook (after-init . global-corfu-mode) + :bind (:map corfu-map + ("" . corfu-complete)) + :config + (setq tab-always-indent 'complete) + (setq corfu-preview-current nil) + (setq corfu-min-width 20)) + +(use-package corfu-popupinfo + :ensure nil + :after corfu + :hook (corfu-mode . corfu-popupinfo-mode) + :custom + (corfu-popupinfo-delay '(0.25 . 0.1)) + (corfu-popupinfo-hide nil) + :config + (corfu-popupinfo-mode)) + +(use-package corfu-terminal + :ensure t + :if (not (display-graphic-p)) + :config + (corfu-terminal-mode)) + +(use-package cape + :ensure t + :init + (add-to-list 'completion-at-point-functions #'cape-dabbrev) + (add-to-list 'completion-at-point-functions #'cape-file)) + +(use-package delsel + :ensure nil + :hook (after-init . delete-selection-mode)) + +(use-package expand-region + :ensure t + :bind + (("M-" . er/expand-region) + ("M-" . er/contract-region))) + +(use-package dtrt-indent + :ensure t + :config + (setq dtrt-indent-verbosity 0) + (setq dtrt-indent-run-after-smie t) + (dtrt-indent-global-mode t)) diff --git a/emacs.d/git.el b/emacs.d/git.el new file mode 100644 index 0000000..10a40b9 --- /dev/null +++ b/emacs.d/git.el @@ -0,0 +1,3 @@ +(use-package magit + :ensure t + :bind (("C-x g" . magit-status))) diff --git a/emacs.d/init.el b/emacs.d/init.el new file mode 100644 index 0000000..1c58242 --- /dev/null +++ b/emacs.d/init.el @@ -0,0 +1,14 @@ +(dolist (f '("packages.el" + "misc.el" + "ui.el" + "dired.el" + "minibuffer.el" + "editing.el" + "dev.el" + "git.el" + "lang-modes.el" + "keybinds.el")) + (load (locate-user-emacs-file f))) + +(setq gc-cons-threshold original-gc-cons-threshold) + diff --git a/emacs.d/keybinds.el b/emacs.d/keybinds.el new file mode 100644 index 0000000..427df4e --- /dev/null +++ b/emacs.d/keybinds.el @@ -0,0 +1,30 @@ +;; move through windows (aka "panes") with C-arrowkeys +(windmove-default-keybindings 'control) + +;; use "normal" (aka. non-default-emacs, or what most other apps do) +;; key bindings for C-z, C-x, C-c and C-v. C-x and C-c only do cut/copy +;; when a region is selected. +(cua-mode) + +;; alternative key binding handler for C-g which does the following: +;; - if a region is active, disable it +;; - when the completions buffer is selected, close it +;; - if the minibuffer is open but not focused, close it +;; - otherwise, run keyboard-quit +(defun prot/keyboard-quit-dwim () + (interactive) + (cond + ((region-active-p) + (keyboard-quit)) + ((derived-mode-p 'completion-list-mode) + (delete-completion-window)) + ((> (minibuffer-depth) 0) + (abort-recursive-edit)) + (t + (keyboard-quit)))) + +(define-key global-map (kbd "C-g") #'prot/keyboard-quit-dwim) + +(global-set-key (kbd "C-x C-S-E") #'eval-buffer) + +(global-set-key (kbd "C-c w") #'whitespace-mode) diff --git a/emacs.d/lang-modes.el b/emacs.d/lang-modes.el new file mode 100644 index 0000000..f00cef0 --- /dev/null +++ b/emacs.d/lang-modes.el @@ -0,0 +1,19 @@ +(use-package emacs-lisp-mode + :hook ((emacs-lisp-mode . gered/on-emacs-list-mode)) + :init + ;; TODO: is this even necessary or was i seeing something odd caused by my own (prior) mistakes? + (defun gered/on-emacs-list-mode () + (setq-local indent-tabs-mode nil) + (setq-local tab-width 2))) + +(use-package yaml-mode + :ensure t) + +(use-package json-mode + :ensure t + :config + (setq js-indent-level 2)) + +(use-package markdown-mode + :ensure t + :hook ((markdown-mode . visual-line-mode))) diff --git a/emacs.d/minibuffer.el b/emacs.d/minibuffer.el new file mode 100644 index 0000000..e137f13 --- /dev/null +++ b/emacs.d/minibuffer.el @@ -0,0 +1,22 @@ +(setopt enable-recursive-minibuffers 1) + +;; use a vertical layout for the minibuffer +(use-package vertico + :ensure t + :hook (after-init . vertico-mode)) + +;; show descriptions for things in the minibuffer +(use-package marginalia + :ensure t + :hook (after-init . marginalia-mode)) + +;; less strict matching for things in the minibuffer +(use-package orderless + :ensure t + :config + (setq completion-styles '(orderless basic)) + (setq completion-category-defaults nil) + (setq completion-category-override nil)) + +;; keep history of minibuffer inputs +(savehist-mode) diff --git a/emacs.d/misc.el b/emacs.d/misc.el new file mode 100644 index 0000000..e78215a --- /dev/null +++ b/emacs.d/misc.el @@ -0,0 +1,33 @@ +(setq initial-major-mode 'fundamental-mode) +(setq ring-bell-function 'ignore) + +(setq sentence-end-double-space nil) + +;; TODO: do i really want to enable this? +;; (setopt auto-revert-avoid-polling t) +;; (setopt auto-revert-interval 5) +;; (setopt auto-revert-check-vc-info t) +;; (global-auto-revert-mode) + +(setq create-lockfiles nil) + +;; put all auto-generated configurations in a separate file +(setq custom-file (locate-user-emacs-file "custom.el")) +(load custom-file :no-error-if-file-is-missing) + +;; better "autosaves" file handling (the `#file#` files) +(setq kill-buffer-delete-auto-save-files t) +(setq auto-save-file-name-transforms + `((".*" ,temporary-file-directory t))) + +;; keep all *~ backup files inside ~/.emacs.d/backup +(defun get-emacsd-backup-file-name (fpath) + "Return a new file path for a given file path. +If the new path's directory does not exist, this will create them." + (let* ((backup-root-dir "~/.emacs.d/backup/") + (file-path (replace-regexp-in-string "[A-Za-z]:" "" fpath)) ; remove Windows drive letter + (backup-file-path (replace-regexp-in-string "//" "/" (concat backup-root-dir file-path "~")))) + (make-directory (file-name-directory backup-file-path) + (file-name-directory backup-file-path)) + backup-file-path)) +(setopt make-backup-file-name-function 'get-emacsd-backup-file-name) diff --git a/emacs.d/packages.el b/emacs.d/packages.el new file mode 100644 index 0000000..4b32b9e --- /dev/null +++ b/emacs.d/packages.el @@ -0,0 +1,9 @@ +(require 'package) +(add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/")) +(package-initialize) + +;; do not show warnings when installing packages +(add-to-list 'display-buffer-alist + '("\\`\\*\\(Warnings\\|Compile-Log\\)\\*\\'" + (display-buffer-no-window) + (allow-no-window . t))) diff --git a/emacs.d/ui.el b/emacs.d/ui.el new file mode 100644 index 0000000..202c6c6 --- /dev/null +++ b/emacs.d/ui.el @@ -0,0 +1,90 @@ +(column-number-mode 1) + +(line-number-mode 1) +(add-hook 'prog-mode-hook 'display-line-numbers-mode) +(setopt display-line-numbers-width 3) + +(add-hook 'text-mode-hook 'visual-line-mode) + +(dolist (hook '(text-mode-hook + prog-mode-hook)) + (add-hook hook 'hl-line-mode)) + +(setopt x-underline-at-descent-line nil) +(setopt switch-to-buffer-obey-display-actions 1) + +(setopt show-trailing-whitespace nil) +(setopt indicate-buffer-boundaries 'left) + +(unless (display-graphic-p) + (xterm-mouse-mode 1)) + +(when (display-graphic-p) + (pixel-scroll-precision-mode 1)) + +(context-menu-mode 1) + +(setopt tab-bar-show 1) + +(let ((mono-spaced-font "Cascadia Code") + (proportionately-spaced-font "Sans")) + (set-face-attribute 'default nil :family mono-spaced-font :height 128) + (set-face-attribute 'fixed-pitch nil :family mono-spaced-font :height 1.0) + (set-face-attribute 'variable-pitch nil :family proportionately-spaced-font :height 1.0)) + +(use-package modus-themes + :ensure t + :config (load-theme 'modus-vivendi-tinted :no-confirm-loading)) +;; (use-package railscasts-reloaded-theme +;; :ensure t +;; :config (load-theme 'railscasts-reloaded :no-confirm-loading)) +;; (use-package doom-themes +;; :ensure t +;; :config (load-theme 'doom-palenight :no-confirm-loading)) + +;; NOTE: Easy way to install the necessary nerd-icons fonts for this to work: +;; M-x nerd-icons-install-fonts + +(use-package nerd-icons + :ensure t) +(use-package nerd-icons-completion + :ensure t + :after marginalia + :config + (add-hook 'marginalia-mode-hook #'nerd-icons-completion-marginalia-setup)) +(use-package nerd-icons-corfu + :ensure t + :after corfu + :config (add-to-list 'corfu-margin-formatters #'nerd-icons-corfu-formatter)) +(use-package nerd-icons-dired + :ensure t + :hook (dired-mode . nerd-icons-dired-mode)) + +(use-package doom-modeline + :ensure t + :init (doom-modeline-mode 1)) + +(use-package rainbow-delimiters + :ensure t + :hook (prog-mode . rainbow-delimiters-mode)) + +(use-package which-key + :ensure t + :init (which-key-mode) + :diminish which-key-mode + :config + (setq which-key-idle-delay 1)) + +(use-package helpful + :ensure t + :bind (([remap describe-function] . helpful-callable) + ([remap describe-variable] . helpful-variable) + ([remap describe-key] . helpful-key) + ([remap describe-command] . helpful-command))) + +(use-package kind-icon + :ensure t + :if (display-graphic-p) + :after corfu + :config + (add-to-list 'corfu-margin-formatters #'kind-icon-margin-formatter))