;; -*- lexical-binding: t; outline-regexp: "^;;; " -*- ;;; gc (setq gc-cons-threshold (* 1024 1024 100)) (add-hook 'emacs-startup-hook #'(lambda () (message "Startup in %s sec with %d garbage collections" (emacs-init-time "%.2f") gcs-done))) ;;; macros (defmacro amy/add-package (name &optional should-require) "Add a package by `NAME' and automatically require it if `SHOULD-REQUIRE' is not nil." `(progn (unless (package-installed-p (quote ,name)) (package-install (quote ,name))) ,(when should-require `(require (quote ,name))))) (defmacro amy/set-key (key func) "Wrapper of `global-set-key' for setting keybinds without directly using the `kbd' function. See the documentation for `kbd' and `global-set-key' to learn about the `KEY' and `FUNC' arguments." `(global-set-key (kbd ,key) ,func)) (defmacro amy/add-hooks (modes &rest args) "Hook into multiple `MODES'. Where `ARGS' is the rest of the arguments passed to `add-hook'. See `add-hook' for more information." (let ((hooks (mapcar (lambda (mode) (intern (concat (symbol-name mode) "-hook"))) modes))) `(mapc (lambda (name) (add-hook name ,@args)) ',hooks))) (defmacro amy/add-languages (&rest langs) "Wrapper of `add-to-list', made specifically to add languages to `auto-mode-alist'. `LANGS' should be a continuous list of pairs containing regexp and mode. See `auto-mode-alist' for more information." `(amy/map-2 ',langs (lambda (rgxp mode-to-assign) (add-to-list 'auto-mode-alist (cons rgxp mode-to-assign))))) ;;; funcs (defun amy/map-2 (list func) "Map function with 2 variables. Where: `LIST' is the list that we are iterating through. `FUNC' is the function to apply to those two elements. `LIST' must ALWAYS be divisible by two." (cond ((> (mod (length list) 2) 0) (error "List is not divisible by 2")) ((eq list nil) t) (t (progn (funcall func (car list) (car (cdr list))) (amy/map-2 (cdr (cdr list)) func))))) (defun amy/get-active-minor-modes () "Function to get a list of all active minor modes." (let ((active-modes)) (mapc (lambda (mode) (condition-case nil (if (and (symbolp mode) (symbol-value mode)) (add-to-list 'active-modes mode)) (error nil))) minor-mode-list) active-modes)) ;;; emacs (setq ring-bell-function nil visible-bell t custom-file (expand-file-name ".emacs.d/custom.el" "~")) (load custom-file t) (set-frame-name "Emacs") (set-frame-font "Iosevka 20") (set-face-attribute 'fixed-pitch nil :font "Iosevka 20") ;;; package (require 'package) (add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t) (add-to-list 'package-archives '( "jcs-elpa" . "https://jcs-emacs.github.io/jcs-elpa/packages/") t) (setq package-archive-priorities '(("melpa" . 5) ("jcs-elpa" . 0))) (package-initialize) ;;; shell (amy/add-package exec-path-from-shell t) (when (memq window-system '(mac ns x pgtk)) (exec-path-from-shell-initialize)) ;;; theme (amy/add-package spacemacs-theme) (load-theme 'spacemacs-light t) ;; code (amy/set-key "C-S-c C-S-c" 'mc/edit-lines) (amy/set-key "C->" 'mc/mark-next-like-this) (amy/set-key "C-<" 'mc/mark-previous-like-this) (amy/set-key "C-c C-<" 'mc/mark-all-like-this) (amy/add-package paredit t) (amy/add-hooks (emacs-lisp-mode lisp-mode clojure-mode) #'paredit-mode) (amy/add-package flycheck t) (amy/add-package flycheck-eglot) (require 'eglot) ;; Install pre-compiled language grammars (amy/add-package treesit-langs t) (treesit-langs-major-mode-setup) ;; TODO: get rid of all of these add-to-list statements (amy/add-languages "\\.ts\\'" typescript-ts-mode "\\.[tj]sx\\'" tsx-ts-mode "\\.js\\'" js-ts-mode) (amy/add-hooks (js-ts-mode tsx-ts-mode typescript-ts-mode) #'eglot-ensure) (amy/add-hooks (js-ts-mode tsx-ts-mode typescript-ts-mode) #'flycheck-mode) ;; TODO: get rid of all of these "eval-after-load"s (with-eval-after-load 'flycheck-posframe (flycheck-posframe-configure-pretty-defaults)) (with-eval-after-load 'flycheck (require 'flycheck-eglot) (add-hook 'flycheck-mode-hook #'flycheck-eglot-mode)) (with-eval-after-load 'eglot (add-to-list 'eglot-server-programs '(js-base-mode . ("typescript-language-server" "--stdio")))) (amy/add-package slime t) (setq inferior-lisp-program "sbcl") (amy/add-package cider t) (amy/add-package corfu t) (global-corfu-mode) (corfu-history-mode) (corfu-echo-mode) (setq corfu-auto t corfu-auto-prefix 2 corfu-auto-delay 0.0 corfu-echo-documentation 0.25 corfu-quit-at-boundary 'separator corfu-preview-current 'insert corfu-preselect-first nil corfu-cycle t tab-always-indent 'complete) (keymap-set corfu-map "TAB" #'corfu-next) (keymap-set corfu-map "S-TAB" #'corfu-previous) (amy/add-package cape t) (add-to-list 'completion-at-point-functions #'cape-file) (add-to-list 'completion-at-point-functions #'cape-dabbrev) (with-eval-after-load 'cape (advice-add 'pcomplete-completions-at-point :around #'cape-wrap-silent) (advice-add 'pcomplete-completions-at-point :around #'cape-wrap-purify)) ;; minibuffer (amy/add-package vertico t) (setq vertico-cycle t vertico-resize nil) (vertico-mode) (amy/add-package marginalia t) (marginalia-mode) (amy/add-package consult t) (amy/set-key "C-x b" #'consult-buffer) (amy/set-key "C-C C-x b" #'consult-buffer-other-window) (amy/set-key "C-C C-x o" #'consult-outline) ;;; completions (amy/add-package orderless t) (setq completion-styles '(orderless basic) completion-category-overrides '((file (styles partial-completion))) completion-pcm-leading-wildcard t) ;;; git ui (amy/add-package magit t) (amy/set-key "M-g g" #'magit) ;;; dired (setq dired-listing-switches "-al --group-directories-first")