;;; ~/.emacs -*- mode: emacs-lisp; lexical-binding: t; -*- ;; Author Case Duckworth ;; Bankruptcy: 12 ;;; Initialization -- see also ~/.emacs.d/early-init.el (setopt custom-file (locate-user-emacs-file "custom.el")) (load custom-file :no-error) (defvar user-private-file (locate-user-emacs-file "private.el") "Private customizations") ;; make sure it's really private! (and (= (file-attribute-user-id (file-attributes user-private-file)) (user-uid)) ; is it owned by this me? (set-file-modes user-private-file #o600)) (load user-private-file :no-error) (load-theme 'brianna :no-confirm) ; see ~/.emacs.d/brianna-theme.el (add-hook 'after-init-hook #'setup-faces) (define-advice startup-echo-area-message (:override ()) (if (get-buffer "*Warnings*") ";_;" "^_^")) ;;; Basic settings ;; Environment (setenv "PAGER" "cat") ; emacs is a pager (setenv "TERM" "dumb") ; no fancy graphics! (setenv "NO_COLOR" "1") ; no color! ;; Startup (setopt inhibit-startup-screen t) (setopt initial-buffer-choice #'eshell) (setopt initial-scratch-message ";; *scratch*") (setopt initial-major-mode #'emacs-lisp-mode) ;; Dialogs (setopt use-dialog-box nil) (setopt use-file-dialog nil) (setopt read-answer-short t) (setopt use-short-answers t) (setopt echo-keystrokes 0.01) ;; Cursor (blink-cursor-mode -1) ;; Whitespace (setopt whitespace-style '(face trailing tabs tab-mark)) (setopt whitespace-global-modes '(not rcirc-mode jabber-chat-mode)) (global-whitespace-mode) (add-hook 'before-save-hook #'delete-trailing-whitespace-except-current-line) (add-hook 'after-init-hook (lambda () (add-hook 'before-save-hook #'indent-buffer+))) (set-face-attribute 'whitespace-tab nil :background nil :foreground "#888") (setf (alist-get 'tab-mark whitespace-display-mappings) '(9 [?· 9] [?» 9] [?\\ 9])) ;;; UI stuff (setopt tab-bar-show 1) ;; Fixed-pitch (package-ensure '(fixed-pitch-mode :url "https://github.com/cstby/fixed-pitch-mode.git")) (require 'fixed-pitch) (setopt cursor-type 'bar) (setopt fixed-pitch-use-extended-default t) (add-to-list 'fixed-pitch-whitelist-hooks 'vc-dir-mode-hook) (hide-minor-mode 'buffer-face-mode) (add-hook 'fixed-pitch-mode-hook #'display-fill-column-indicator-mode) ;;; Completions (setopt tab-always-indent 'complete) (setopt completion-styles '(basic partial-completion substring flex)) (setopt completion-ignore-case t) (setopt read-buffer-completion-ignore-case t) (setopt read-file-name-completion-ignore-case t) (setopt completion-flex-nospace t) (setopt completion-show-help nil) (setopt completions-detailed t) (setopt completions-group t) (setopt completion-auto-help 'visible) (setopt completion-auto-select 'second-tab) (setopt completions-header-format nil) (setopt completions-format 'one-column) (setopt completions-max-height 10) (keymap-set minibuffer-local-map "C-p" #'minibuffer-previous-completion) (keymap-set minibuffer-local-map "C-n" #'minibuffer-next-completion) (keymap-set minibuffer-local-map "M-DEL" #'minibuffer-delete-directory) (setopt enable-recursive-minibuffers t) (setopt minibuffer-default-prompt-format " [%s]") (minibuffer-depth-indicate-mode) (minibuffer-electric-default-mode) (setopt file-name-shadow-properties '(invisible t intangible t)) (file-name-shadow-mode) (setopt history-length t) (setopt history-delete-duplicates t) (setopt savehist-save-minibuffer-history t) (setopt savehist-autosave-interval 5) (savehist-mode) (define-minor-mode truncate-lines-local-mode "Toggle `truncate-lines' in the current buffer." :lighter "" (setq-local truncate-lines truncate-lines-local-mode)) (add-hook 'completion-list-mode-hook #'truncate-lines-local-mode) (add-hook 'minibuffer-setup-hook #'truncate-lines-local-mode) (package-ensure 'visual-fill-column) (setopt visual-fill-column-enable-sensible-window-split t) (add-hook 'visual-line-mode-hook #'visual-fill-column-mode) (advice-add 'text-scale-adjust :after #'visual-fill-column-adjust) (package-ensure 'adaptive-wrap) (add-hook 'visual-fill-column-mode #'adaptive-wrap-prefix-mode) ;; Consult/Marginalia (package-ensure 'consult) (require 'consult) (keymap-global-set "C-x b" #'consult-buffer) (keymap-global-set "C-x 4 b" #'consult-buffer-other-window) (keymap-global-set "C-x 5 b" #'consult-buffer-other-frame) (keymap-global-set "C-x r b" #'consult-bookmark) (keymap-global-set "M-y" #'consult-yank-pop) (keymap-global-set "M-g g" #'consult-goto-line) (keymap-global-set "M-g M-g" #'consult-goto-line) (keymap-global-set "M-g o" #'consult-outline) (keymap-global-set "M-g m" #'consult-mark) (keymap-global-set "M-g i" #'consult-imenu) (keymap-global-set "M-s d" #'consult-find) (keymap-global-set "M-s D" #'consult-locate) (keymap-global-set "M-s l" #'consult-line) (keymap-global-set "M-s k" #'consult-keep-lines) (keymap-global-set "M-s u" #'consult-focus-lines) (keymap-global-set "M-s e" #'consult-isearch-history) (keymap-set isearch-mode-map "M-e" #'consult-isearch-history) (keymap-set isearch-mode-map "M-s e" #'consult-isearch-history) (keymap-set isearch-mode-map "M-s l" #'consult-line) (setopt xref-show-xrefs-function #'consult-xref) (setopt xref-show-definitions-function #'xref-show-definitions-completing-read) (setopt consult-preview-key "M-.") (package-ensure 'marginalia) (marginalia-mode) ;;; Frames / Windows (winner-mode) ;;; Files (setopt auto-revert-verbose nil) (setopt global-auto-revert-non-file-buffers t) (global-auto-revert-mode) (setopt create-lockfiles nil) (setopt mode-require-final-newline t) (setopt view-read-only t) (setopt save-silently t) (setopt delete-by-moving-to-trash t) (setopt auto-save-default nil) (setopt auto-save-no-message t) (setopt auto-save-interval 2) (setopt auto-save-timeout 2) (setopt auto-save-visited-interval 5) (setopt remote-file-name-inhibit-auto-save t) (setopt remote-file-name-inhibit-auto-save-visited t) (add-to-list 'auto-save-file-name-transforms `(".*" ,(locate-user-emacs-file "auto-save/") t)) (auto-save-visited-mode) (add-function :after after-focus-change-function (defun focus-out-save () (save-some-buffers t))) (setopt backup-by-copying t) (setopt version-control t) (setopt kept-new-versions 3) (setopt kept-old-versions 3) (setopt delete-old-versions t) (add-to-list 'backup-directory-alist '("^/dev/shm/" . nil)) (add-to-list 'backup-directory-alist '("^/tmp/" . nil)) (when-let ((xrd (getenv "XDG_RUNTIME_DIR"))) (add-to-list 'backup-directory-alist (cons xrd nil))) (add-to-list 'backup-directory-alist (cons "." (locate-user-emacs-file "backup/")) :append) (setopt recentf-max-menu-items 100) (setopt recentf-max-saved-items nil) (setopt recentf-case-fold-search t) (with-eval-after-load 'recentf (add-to-list 'recentf-exclude "-autoloads.el\\'")) (add-hook 'buffer-list-update-hook #'recentf-track-opened-file) (add-hook 'after-save-hook #'recentf-save-list) (recentf-mode) (setopt save-place-forget-unreadable-files (eq system-type 'gnu/linux)) (save-place-mode) (add-hook 'find-file-not-found-functions #'create-missing-directories) ;;; Buffers ;; Unique names (setopt uniquify-buffer-name-style 'forward) ;; Persistent undo (package-ensure 'undo-fu-session) (setopt undo-fu-session-incompatible-files '("/COMMIT_EDITMSG\\'" "/git-rebase-todo\\'")) (undo-fu-session-global-mode) ;; Encodings (set-language-environment "UTF-8") (setopt buffer-file-coding-system 'utf-8-unix) (setopt coding-system-for-read 'utf-8-unix) (setopt coding-system-for-write 'utf-8-unix) (setopt default-process-coding-system '(utf-8-unix . utf-8-unix)) (setopt locale-coding-system 'utf-8-unix) (set-charset-priority 'unicode) (prefer-coding-system 'utf-8-unix) (set-default-coding-systems 'utf-8-unix) (set-terminal-coding-system 'utf-8-unix) (set-keyboard-coding-system 'utf-8-unix) (pcase system-type ((or 'ms-dos 'windows-nt) (set-clipboard-coding-system 'utf-16-le) (set-selection-coding-system 'utf-16-le)) (_ (set-selection-coding-system 'utf-8) (set-clipboard-coding-system 'utf-8))) ;;; Search (setopt isearch-lazy-count t) (setopt isearch-regexp-lax-whitespace t) (setopt isearch-wrap-pause 'no) (setopt search-whitespace-regexp "[ ]+") (setopt search-ring-max 256) (setopt regexp-search-ring-max 256) (define-advice isearch-cancel (:before () add-to-history) "Add search string to history when canceling isearch." (unless (string-equal "" isearch-string) (isearch-update-ring isearch-string isearch-regexp))) (package-ensure 'isearch-mb) (with-eval-after-load 'isearch-mb (with-eval-after-load 'consult (add-to-list 'isearch-mb--with-buffer #'consult-isearch-history) (keymap-set isearch-mb-minibuffer-map "M-r" #'consult-isearch-history) (add-to-list 'isearch-mb--after-exit #'consult-line) (keymap-set isearch-mb-minibuffer-map "M-s l" #'consult-line))) (isearch-mb-mode) ;; Default to regexen (setopt search-default-mode t) ; Isearch (keymap-global-set "M-%" #'query-replace-regexp) (keymap-global-set "C-M-%" #'query-replace) ;;; Keybinds (keymap-global-set "C-x C-k" #'kill-buffer-dwim) (keymap-global-set "M-o" #'other-window-dwim) (keymap-global-set "C-x o" #'other-window-dwim) (keymap-global-set "C-x 0" #'delete-window-dwim) (keymap-global-set "M-SPC" #'cycle-spacing*) (keymap-global-set "C-M-\\" #'indent-buffer+) (keymap-global-set "C-x C-c" #'save-buffers-kill*) (keymap-global-set "C-x C-b" #'ibuffer) (keymap-global-set "M-/" #'hippie-expand) (keymap-global-set "M-u" #'universal-argument) (keymap-set universal-argument-map "M-u" #'universal-argument-more) (keymap-global-set "C-c s" #'eshell) (keymap-global-set "C-c d" (defun insert-current-iso8601 () (interactive) (insert (format-time-string "%FT%TZ" (current-time) t)))) (keymap-global-set "C-c i" (define-keymap :prefix 'find-init-map "i" (find-user-file init) "e" (find-user-file early-init (locate-user-emacs-file "early-init.el")) "c" (find-user-file custom custom-file) "p" (find-user-file private) "t" (find-user-file brianna (locate-user-emacs-file "brianna-theme.el")) "s" #'scratch-buffer)) (keymap-global-set "C-c t" (define-keymap :prefix 'toggle-map "e" #'toggle-debug-on-error "q" #'toggle-debug-on-quit "c" #'column-number-mode "l" #'line-number-mode "L" #'display-line-numbers-mode "t" #'truncate-lines-local-mode)) ;; Un-keybinds (keymap-global-unset "C-" t) (keymap-global-unset "C-" t) ;; I only ever fat-finger this key and never want to change encoding (keymap-global-unset "C-\\" t) (keymap-global-unset "C-z" t) ;; Key settings (setopt set-mark-command-repeat-pop t) ;;; Text-editing packages ;; Hungry delete (package-ensure 'hungry-delete) (setopt hungry-delete-chars-to-skip " \t") (with-eval-after-load 'hungry-delete (add-to-list 'hungry-delete-except-modes 'eshell-mode) (add-to-list 'hungry-delete-except-modes 'eww-mode)) (global-hungry-delete-mode) ;;; Writing (add-hook 'text-mode-hook #'visual-line-mode) ;;; Programming (add-hook 'prog-mode-hook #'electric-pair-local-mode) (setopt tab-width 8) (setopt sh-basic-offset tab-width) (setopt perl-indent-level tab-width) (setopt c-basic-offset tab-width) (defvar space-indent-modes '(emacs-lisp-mode lisp-interaction-mode lisp-mode scheme-mode python-mode haskell-mode text-mode web-mode css-mode) "Modes to indent with spaces, not tabs.") (add-hook 'prog-mode-hook (defun indent-tabs-mode-maybe () (setq indent-tabs-mode (if (apply #'derived-mode-p space-indent-modes) nil t)))) ;; Elisp (keymap-set emacs-lisp-mode-map "C-c C-c" #'eval-defun) (keymap-set emacs-lisp-mode-map "C-c C-b" (defun eval-buffer@pulse () (interactive) (eval-buffer) (pulse-momentary-highlight-region (point-min) (point-max)))) (advice-add 'eval-region :after #'pulse@eval) (add-hook 'emacs-lisp-mode-hook #'elisp-enable-lexical-binding) ;; Makefile (setopt makefile-backslash-align nil) (setopt makefile-cleanup-continuations t) (add-hook 'makefile-mode-hook (defun makefile-stop-complaining () (remove-hook 'write-file-functions 'makefile-warn-suspicious-lines t) (remove-hook 'write-file-functions 'makefile-warn-continuations t))) ;; Scheme -- CHICKEN (setopt scheme-program-name (or (executable-find "csi"))) (add-to-list 'auto-mode-alist '("\\.egg\\'" . scheme-mode)) ;; Scheme Indentation (defun scheme-module-indent (state indent-point normal-indent) 0) (put 'module 'scheme-indent-function 'scheme-module-indent) (put 'and-let* 'scheme-indent-function 1) (put 'parameterize 'scheme-indent-function 1) (put 'handle-exceptions 'scheme-indent-function 1) (put 'when 'scheme-indent-function 1) (put 'unless 'scheme-indent-function 1) (put 'match 'scheme-indent-function 1) ;; Geiser (package-ensure 'geiser) (package-ensure 'geiser-chicken) (setopt geiser-mode-auto-p nil) (setopt geiser-repl-history-filename "~/.emacs.d/geiser-history") (setopt geiser-chicken-init-file "~/.csirc") (add-hook 'scheme-mode-hook #'geiser-mode) (add-hook 'geiser-repl-mode-hook #'electric-pair-local-mode) (advice-add 'geiser-eval-region :after #'pulse@eval) ;; VC (keymap-global-set "C-x v j" (defun vc-jump () (interactive) (vc-dir default-directory))) ;;; Compilation (setopt compilation-always-kill t) (setopt compilation-ask-about-save nil) ;;; Languages (package-ensure 'gemtext-mode) ;;; Miscellaneous settings (add-hook 'after-save-hook #'executable-make-buffer-file-executable-if-script-p) (add-hook 'prog-mode-hook #'auto-fill-mode) (add-hook 'prog-mode-hook #'electric-pair-local-mode) (setopt x-underline-at-descent-line t) (setopt scroll-conservatively 101) (setopt display-fill-column-indicator-character ?·) (setopt disabled-command-function nil) (setopt electric-pair-skip-whitespace 'chomp) (setopt fill-column 80) (setopt finger-X.500-host-regexps '(".*tilde.*")) (setopt recenter-positions '(top middle bottom)) (setopt eval-expression-print-level nil) (setopt eval-expression-print-length nil) (setopt show-paren-delay 0.01) (setopt show-paren-style 'parenthesis) (setopt show-paren-when-point-in-periphery t) (setopt show-paren-when-point-inside-paren t) (show-paren-mode) (delete-selection-mode) (global-so-long-mode) (global-goto-address-mode) (context-menu-mode) (tooltip-mode -1) (add-hook 'special-mode-hook (defun hl-line@special-mode () (unless (derived-mode-p 'help-mode ; add other modes here 'Info-mode 'eww-mode) (hl-line-mode)))) (add-hook 'dired-mode-hook #'hl-line-mode) ;;; RCIRC (setopt rcirc-kill-channel-buffers t) (setopt rcirc-display-server-buffer nil) (defun run-rcirc () (interactive) (shell-command "chat up") (call-interactively #'rcirc)) (add-hook 'rcirc-mode-hook (defun @rcirc () (rcirc-track-minor-mode) (rcirc-omit-mode) (visual-line-mode) (setq default-directory (expand-file-name "~")))) ;;; Jabber (package-ensure 'jabber) (with-eval-after-load 'jabber (require 'jabber-httpupload nil t) ;; I wish jabber.el didn't clobber C-x C-j ... (keymap-global-set "C-x C-j" #'dired-jump) (keymap-global-set "C-c j" jabber-global-keymap) (map-keymap (lambda (key cmd) (define-key jabber-global-keymap (vector (+ key #x60)) cmd)) jabber-global-keymap) ;; This is just a dang good idea (keymap-global-set "C-c C-SPC" #'jabber-activity-switch-to)) (setopt jabber-activity-make-strings #'jabber-activity-make-strings-shorten) (setopt jabber-activity-query-unread nil) (setopt jabber-auto-reconnect t) (setopt jabber-browse-buffer-format "%n") (setopt jabber-chat-buffer-format "%n") (setopt jabber-groupchat-buffer-format "%b") (setopt jabber-muc-private-buffer-format "%n<%g>") (add-hook 'jabber-post-connect-hooks #'jabber-enable-carbons) (add-hook 'jabber-chat-mode-hook #'visual-line-mode) (remove-hook 'jabber-alert-muc-hooks #'jabber-muc-echo) (remove-hook 'jabber-alert-presence-hooks #'jabber-presence-echo) ;;; Eshell (setopt eshell-banner-message (format "%s\n\n" (mapconcat #'identity (process-lines "fortune" "-s") "\n"))) (setopt eshell-prompt-function (defun @eshell-prompt () (let ((rootp (zerop (user-uid)))) (concat "( " (abbreviate-file-name (eshell/pwd)) (if rootp ":root" "") " ) ")))) (setopt eshell-prompt-regexp "^(.*) ") ;;; Browsing ;; Dired (files) (setopt dired-dwim-target t) (setopt dired-listing-switches "-AlF") (setopt dired-ls-F-marks-symlinks t) (setopt dired-recursive-copies 'always) (setopt dired-recursive-deletes 'always) (setopt dired-auto-revert-buffer t) (setopt dired-hide-details-hide-symlink-targets nil) (add-hook 'dired-mode-hook #'dired-hide-details-mode) (add-hook 'dired-mode-hook #'truncate-lines-local-mode) (with-eval-after-load 'dired (require 'dired-x) (keymap-set dired-mode-map "C-j" #'dired-up-directory) (setopt dired-omit-files (regexp-concat dired-omit-files "^\\..+$" ;; CHICKEN ... this may be overkill "\\.s?o$" "\\.import\\.scm$" "\\.\\(build\\|install\\)\\.sh$" "\\.link$")) (add-hook 'dired-mode-hook #'dired-omit-mode) (keymap-set dired-mode-map ")" #'dired-omit-mode)) ;; Elpher (gemini/gopher) (package-ensure 'elpher) ;;; HTTP browsing ;; SHR (setopt shr-max-width (+ fill-column 10)) ;; Browse-url (setopt browse-url-new-window-flag t) (setopt browse-url-firefox-arguments '("--new-tab")) (setopt browse-url-firefox-new-window-is-tab t)