From 75137467d90494170a2c0cd34489954196b6416a Mon Sep 17 00:00:00 2001 From: Case Duckworth Date: Mon, 10 Jun 2024 23:11:15 -0500 Subject: Update init --- emacs | 406 ++++++++++++++++++-------------------------------- emacs.d/early-init.el | 30 +++- 2 files changed, 169 insertions(+), 267 deletions(-) diff --git a/emacs b/emacs index 7b3d9ea..a54028e 100644 --- a/emacs +++ b/emacs @@ -1,4 +1,4 @@ -;;; ~/.emacs -*- lexical-binding: t; -*- +;;; ~/.emacs -*- mode: emacs-lisp; lexical-binding: t; -*- ;; Author Case Duckworth ;; Bankruptcy: 12 @@ -7,179 +7,34 @@ (setopt custom-file (locate-user-emacs-file "custom.el")) (load custom-file :no-error) -(defvar private-file (locate-user-emacs-file "private.el") +(defvar user-private-file (locate-user-emacs-file "private.el") "Private customizations") -(load private-file :no-error) ; might as well do this now +;; 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 'modus-operandi :no-confirm) - -;;; Custom functions +(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*") ";_;" "^_^")) -(defun create-missing-directories () - "Automatically create missing directories." - (let ((target-dir (file-name-directory buffer-file-name))) - (unless (file-exists-p target-dir) - (make-directory target-dir :parents)))) - -(defun delete-trailing-whitespace-except-current-line () - (save-excursion - (delete-trailing-whitespace (point-min) - (line-beginning-position)) - (delete-trailing-whitespace (line-end-position) - (point-max)))) - -(defun run-after-frame-init (func) - "Run FUNC after the first frame is initialized. -If already so, run FUNC immediately." - (cond - ((daemonp) - (add-hook 'server-after-make-frame-hook func) - (advice-add func :after (lambda () - (remove-hook 'server-after-make-frame-hook - func) - (advice-remove func - 'after-frame-init-removing-advice)) - - - '((name . after-frame-init-removing-advice)))) - ((not after-init-time) - (add-hook 'after-init-hook func)) - (:else (funcall func)))) - -(defun first-found-font (&rest cands) - "Return the first font of CANDS that is installed, or nil." - (cl-loop with ffl = (font-family-list) - for font in cands - if (member font ffl) - return font)) - -(defun setup-faces () - "Setup Emacs faces." - (set-face-attribute 'variable-pitch nil - :family (first-found-font "Public Sans") - :height 1.0) - (set-face-attribute 'fixed-pitch nil - :family (first-found-font "Recursive Mono Linear Static")) - (set-face-attribute 'fixed-pitch-serif nil - :family (first-found-font "Go Mono" - "DejaVu Sans Mono")) - - ;; Emojis - (cl-loop with ffl = (font-family-list) - for font in '("Noto Emoji" "Noto Color Emoji" - "Segoe UI Emoji" "Apple Color Emoji" - "FreeSans" "FreeMono" "FreeSerif" - "Unifont" "Symbola") - if (member font ffl) - do (set-fontset-font t 'symbol font)) - - ;; International fonts - (cl-loop with ffl = (font-family-list) - for (charset . font) - in '((latin . "Noto Sans") - (han . "Noto Sans CJK SC Regular") - (kana . "Noto Sans CJK JP Regular") - (hangul . "Noto Sans CJK KR Regular") - (cjk-misc . "Noto Sans CJK KR Regular") - (khmer . "Noto Sans Khmer") - (lao . "Noto Sans Lao") - (burmese . "Noto Sans Myanmar") - (thai . "Noto Sans Thai") - (ethiopic . "Noto Sans Ethiopic") - (hebrew . "Noto Sans Hebrew") - (arabic . "Noto Sans Arabic") - (gujarati . "Noto Sans Gujarati") - (devanagari . "Noto Sans Devanagari") - (kannada . "Noto Sans Kannada") - (malayalam . "Noto Sans Malayalam") - (oriya . "Noto Sans Oriya") - (sinhala . "Noto Sans Sinhala") - (tamil . "Noto Sans Tamil") - (telugu . "Noto Sans Telugu") - (tibetan . "Noto Sans Tibetan")) - if (member font ffl) - do (set-fontset-font t charset font))) - -(defmacro inhibit-messages (&rest body) - "Inhibit all messages in BODY." - (declare (indent defun)) - `(cl-letf (((symbol-function 'message) #'ignore)) - ,@body)) - -(defun kill-buffer-dwim (&optional buffer-or-name) - "Kill BUFFER-OR-NAME or the current buffer." - (interactive "P") - (cond - ((bufferp buffer-or-name) - (kill-buffer buffer-or-name)) - ((null buffer-or-name) - (kill-current-buffer)) - (:else - (kill-buffer (read-buffer "Kill: " nil :require-match))))) - -(defun other-window-dwim (&optional arg) - "Switch to another window/buffer. -Calls `other-window', which see, unless -- the current window is alone on its frame -- `other-window-dwim' is called with \\[universal-argument] -In these cases, switch to the last-used buffer." - (interactive "P") - (if (or arg (one-window-p)) - (switch-to-buffer (other-buffer) nil t) - (other-window 1))) - -(defun delete-window-dwim () - "Delete the current window or bury its buffer. -If the current window is alone in its frame, bury the buffer -instead." - (interactive) - (unless (ignore-errors (delete-window) t) - (bury-buffer))) - -(defun cycle-spacing* (&optional n) - "Negate N argument on `cycle-spacing'." - (interactive "*p") - (cycle-spacing (- n))) - -(defun find-user-init-file (&optional arg) - "Edit `user-init-file' in current window. -With ARG, edit in other window." - (interactive "P") - (funcall (if arg #'find-file-other-window #'find-file) - user-init-file)) - -(defun find-user-private-file (&optional arg) - "Edit `private-file'. -With ARG, edit in other window." - (interactive "P") - (funcall (if arg #'find-file-other-window #'find-file) - private-file)) - -(defun package-ensure (pkg) - "Install PKG if it's not already installed." - (unless (package-installed-p pkg) - (package-install pkg))) - -(defun minibuffer-delete-directory () - (interactive) - (let ((here (point)) - (meta (completion-metadata - "" minibuffer-completion-table - minibuffer-completion-predicate))) - (if (eq (completion-metadata-get meta 'category) 'file) - (when (search-backward "/" (minibuffer-prompt-end) t) - (delete-region (point) here)) - (backward-kill-word 1)))) - ;;; Basic settings -(recancel-colors) -(tooltip-mode -1) +;; 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) @@ -191,21 +46,28 @@ With ARG, edit in other window." ;; Cursor (blink-cursor-mode -1) -;; Fonts -(setopt x-underline-at-descent-line t) -(run-after-frame-init #'setup-faces) - -;;; Look and feel - ;; Whitespace (setopt whitespace-style '(face trailing tabs tab-mark)) -(setopt whitespace-global-modes '(not rcirc-mode)) +(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")) +(setopt cursor-type 'bar) +(require 'fixed-pitch) +(add-to-list 'fixed-pitch-whitelist-hooks 'vc-dir-mode-hook) + ;;; Completions (setopt tab-always-indent 'complete) @@ -251,6 +113,14 @@ With ARG, edit in other window." (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) @@ -275,8 +145,7 @@ With ARG, edit in other window." (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 xref-show-definitions-function #'xref-show-definitions-completing-read) (setopt consult-preview-key "M-.") (package-ensure 'marginalia) @@ -375,7 +244,7 @@ With ARG, edit in other window." (setopt isearch-lazy-count t) (setopt isearch-regexp-lax-whitespace t) (setopt isearch-wrap-pause 'no) -(setopt search-whitespace-regexp ".*?") ; swiper-style +(setopt search-whitespace-regexp "[ ]+") (setopt search-ring-max 256) (setopt regexp-search-ring-max 256) @@ -400,18 +269,18 @@ With ARG, edit in other window." ;;; Keybinds -(keymap-global-set "C-x C-c" #'save-buffers-kill-terminal) (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 i" #'find-user-init-file) -(keymap-global-set "C-c p" #'find-user-private-file) (keymap-global-set "C-c s" #'eshell) (keymap-global-set "C-c d" @@ -419,14 +288,17 @@ With ARG, edit in other window." (interactive) (insert (format-time-string "%FT%TZ" (current-time) t)))) -(keymap-global-set "C-M-\\" - (defun indent-buffer () - (interactive) - (save-mark-and-excursion - (indent-region (point-min) (point-max)) - (if (apply #'derived-mode-p space-indent-modes) - (untabify (point-min) (point-max)) - (tabify (point-min) (point-max)))))) +(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 @@ -448,47 +320,19 @@ With ARG, edit in other window." ;; Key settings (setopt set-mark-command-repeat-pop t) -;;; Writing - -(add-hook 'text-mode-hook #'visual-line-mode) -(add-hook 'text-mode-hook #'auto-fill-mode) - -;;; Hungry delete -;; I was using the hungry-delete package, but it turns out I can get *most* of -;; the features with just these functions. - -(defun %hungry-delete (skip-fn del-key) - (let ((here (point))) - (funcall skip-fn " \t") - (if (or (= (point) here) - (apply 'derived-mode-p - '(eshell-mode ; add other modes to skip here. - nim-mode - pyton-mode))) - (call-interactively (keymap-lookup (list (current-local-map) - (current-global-map)) - del-key)) - (delete-region (point) here)))) - -(defun hungry-delete-forward () - "Delete forward, hungrily." - (interactive) - (%hungry-delete #'skip-chars-forward "C-d")) +;;; Text-editing packages -(defun hungry-delete-backward () - "Delete backward, hungrily." - (interactive) - (%hungry-delete #'skip-chars-backward "DEL")) +;; 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) -(define-minor-mode hungry-delete-mode - "Hungrily delete stuff." - :global t - :lighter " h" - :keymap (define-keymap - "DEL" #'hungry-delete-backward - "C-d" #'hungry-delete-forward)) +;;; Writing -(hungry-delete-mode) +(add-hook 'text-mode-hook #'visual-line-mode) ;;; Programming @@ -498,17 +342,6 @@ With ARG, edit in other window." (setopt perl-indent-level tab-width) (setopt c-basic-offset tab-width) -;; Elisp -(defun pulse@eval (start end &rest _) - (pulse-momentary-highlight-region start end)) - -(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@eval (point-min) (point-max)))) -(advice-add 'eval-region :after #'pulse@eval) - (defvar space-indent-modes '(emacs-lisp-mode lisp-interaction-mode lisp-mode @@ -520,10 +353,19 @@ With ARG, edit in other window." css-mode) "Modes to indent with spaces, not tabs.") -(defun indent-tabs-mode-maybe () - (setq indent-tabs-mode - (if (apply #'derived-mode-p space-indent-modes) nil t))) -(add-hook 'prog-mode-hook #'indent-tabs-mode-maybe) +(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) @@ -561,11 +403,10 @@ With ARG, edit in other window." (advice-add 'geiser-eval-region :after #'pulse@eval) ;; VC -(add-hook 'vc-dir-mode-hook #'hl-line-mode) -(defun vc-jump () - (interactive) - (vc-dir default-directory)) -(keymap-global-set "C-x v j" #'vc-jump) +(keymap-global-set "C-x v j" + (defun vc-jump () + (interactive) + (vc-dir default-directory))) ;;; Compilation @@ -582,15 +423,13 @@ With ARG, edit in other window." (add-hook 'prog-mode-hook #'auto-fill-mode) (add-hook 'prog-mode-hook #'electric-pair-local-mode) (global-display-fill-column-indicator-mode) -(delete-selection-mode) -(global-so-long-mode) -(global-goto-address-mode) -(context-menu-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) @@ -599,12 +438,19 @@ With ARG, edit in other window." (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) -(with-eval-after-load 'ibuffer - (add-hook 'ibuffer-mode-hook #'hl-line-mode)) - -(with-eval-after-load 'proced - (add-hook 'proced-mode-hook #'hl-line-mode)) +(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 @@ -623,6 +469,33 @@ With ARG, edit in other window." (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 @@ -632,12 +505,10 @@ With ARG, edit in other window." (setopt eshell-prompt-function (defun @eshell-prompt () (let ((rootp (zerop (user-uid)))) - (propertize - (concat "( " + (concat "( " (abbreviate-file-name (eshell/pwd)) (if rootp ":root" "") - " ) ") - 'face 'bold)))) + " ) ")))) (setopt eshell-prompt-regexp "^(.*) ") ;;; Browsing @@ -650,17 +521,30 @@ With ARG, edit in other window." (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) - (add-hook 'dired-mode-hook #'dired-hide-details-mode) - (add-hook 'dired-mode-hook #'hl-line-mode) - (add-hook 'dired-mode-hook #'truncate-lines-local-mode) - (keymap-set dired-mode-map "C-j" #'dired-up-directory)) + (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) -;; Browse-url (http) +;;; 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) diff --git a/emacs.d/early-init.el b/emacs.d/early-init.el index 2a4f2b5..7374bd1 100644 --- a/emacs.d/early-init.el +++ b/emacs.d/early-init.el @@ -1,4 +1,4 @@ -;;; ~/.emacs.d/early-init.el -*- lexical-binding: t -*- +;;; ~/.emacs.d/early-init.el -*- lexical-binding: t; -*- ;; Author: Case Duckworth (setopt frame-inhibit-implied-resize t) @@ -12,18 +12,19 @@ (defvar *fonts* '((default - :family ("Recursive Mono Casual Static" "DejaVu Sans Mono") + :family ;;("Recursive Mono Casual Static" "DejaVu Sans Mono") + ("Public Sans" "DejaVu Sans") :height 100) (variable-pitch :family ("Public Sans" "DejaVu Sans") :height 1.0) (fixed-pitch - :family ("Recursive Mono Linear Static" "DejaVu Sans Mono")) + :family ("Recursive Mono Casual Static" "DejaVu Sans Mono")) (fixed-pitch-serif :family ("Recursive Mono Linear Static" "DejaVu Sans Mono")))) (require 'package) -(add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t) +(add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/")) (package-initialize) ;;; Custom functions @@ -81,7 +82,7 @@ If already so, run FUNC immediately." :height (or (plist-get spec :height) 'unspecified))) ;; Specialized fonts - (cl-loop with ffl = (font-family-alist) + (cl-loop with ffl = (font-family-list) for (charset . font) in '((latin . "Noto Sans") (han . "Noto Sans CJK SC Regular") @@ -183,7 +184,7 @@ Whether it tabifies or untabifies depends on `space-indent-modes'." (defun package-ensure (pkg) "Install PKG if it's not already installed." (unless (package-installed-p pkg) - (package-install pkg))) + (package-vc-install pkg))) (defun minibuffer-delete-directory () "Delete the last directory in a file-completing minibuffer." @@ -196,3 +197,20 @@ Whether it tabifies or untabifies depends on `space-indent-modes'." (when (search-backward "/" (minibuffer-prompt-end) t) (delete-region (point) here)) (backward-kill-word 1)))) + +(defun save-buffers-kill* (arg) + "Save all the buffers and kill ... something. +If ARG is 1 (called normally), kill the current terminal. +If ARG is 4 (with C-u), kill emacs but ask if there are processes running. +If ARG is 16, kill emacs without asking about processes." + (interactive "p") + (pcase arg + (1 (save-buffers-kill-terminal)) + (4 (save-buffers-kill-emacs t)) + (16 (let ((confirm-kill-processes nil) + (kill-emacs-query-functions nil) + (confirm-kill-emacs nil)) + (save-buffers-kill-emacs t))))) + +(defun regexp-concat (&rest regexps) + (string-join regexps "\\|")) -- cgit 1.4.1-21-gabe81