From c64216002b685cce810b3ba23eed6e4337b73dae Mon Sep 17 00:00:00 2001 From: Case Duckworth Date: Tue, 22 Sep 2020 20:16:01 -0500 Subject: Rewrite to take advantage of outshine-mode --- early-init.el | 127 +++--- init.el | 1386 +++++++++++++++++++++++++++++++-------------------------- 2 files changed, 819 insertions(+), 694 deletions(-) diff --git a/early-init.el b/early-init.el index e7595a9..c67eadb 100644 --- a/early-init.el +++ b/early-init.el @@ -1,60 +1,67 @@ -;;; early-init.el ~ acdw - -;;; this needs to happen first -- speed up init -(setq gc-cons-threshold most-positive-fixnum) -(defvar file-name-handler-alist-old file-name-handler-alist) -(setq file-name-handler-alist nil) -(setq message-log-max 16384) -(setq byte-compile-warnings - '(not free-vars unresolved noruntime lexical make-local)) - -(add-hook 'after-init-hook - (lambda () - (setq file-name-handler-alist file-name-handler-alist-old) - (setq gc-cons-threshold (* 32 1024 1024))) - t) - -;;(setq debug-on-error t) - -;;; different platforms -(defconst *acdw/at-work* (eq system-type 'windows-nt)) -(defconst *acdw/at-larry* (string= (system-name) "larry")) -(defconst *acdw/at-bax* (string= (system-name) "bax")) -(defconst *acdw/at-home* (or *acdw/at-larry* *acdw/at-bax*)) - -;; this needs to be before bootstrapping straight.el -(when *acdw/at-work* - (add-to-list 'exec-path "~/bin") - (add-to-list 'exec-path "C:/Users/aduckworth/Downloads/PortableGit/bin")) - -;;; gui -(add-to-list 'default-frame-alist '(tool-bar-lines . 0)) -(add-to-list 'default-frame-alist '(menu-bar-lines . 0)) - -(setq inhibit-startup-buffer-menu t) -(setq inhibit-startup-screen t) -(setq initial-buffer-choice t) -(setq initial-scratch-message nil) - -;;; straight.el ~ github.com/raxod502/straight.el - -(setq straight-use-package-by-default t) ; use use-package -(setq use-package-hook-name-suffix nil) ; don't assume -hook - -;; bootstrap -(defvar bootstrap-version) -(let ((bootstrap-file - (expand-file-name "straight/repos/straight.el/bootstrap.el" - user-emacs-directory)) - (bootstrap-version 5)) - (unless (file-exists-p bootstrap-file) - (with-current-buffer - (url-retrieve-synchronously - "https://raw.githubusercontent.com/raxod502/straight.el/develop/install.el" - 'silent 'inhibit-cookies) - (goto-char (point-max)) - (eval-print-last-sexp))) - (load bootstrap-file nil 'nomessage)) - -;; install use-package with straight -(straight-use-package 'use-package) +;;; early-init.el ~ acdw -*- lexical-binding: t; coding: utf-8; fill-column: 85 -*- + +;;; Commentary: +;; `early-init.el' is new as of Emacs 27.1. It contains ... /early initiation/. +;; What does that mean? Who knows. What I /do know/ is that it runs /before/ +;; `package.el' is loaded, so I can stop it from loading, since I use `straight.el'. +;; Other than that, there's some other init stuff that needs to happen as early +;; as possible -- think bootstrap-level. + +;;; Speed up startup +(setq gc-cons-threshold most-positive-fixnum) + +(defvar file-name-handler-alist-old file-name-handler-alist) +(setq file-name-handler-alist nil) + +(setq message-log-max 16384) +(setq byte-compile-warnings + '(not free-vars unresolved noruntime lexical make-local)) + +;;; Restore stuff after startup +(add-hook 'after-init-hook + (lambda () + (setq file-name-handler-alist file-name-handler-alist-old) + (setq gc-cons-threshold (* 32 1024 1024)) + (garbage-collect)) + t) + +;; (setq debug-on-error t) + +;;; Define the platforms I work on +(defconst *acdw/at-work* (eq system-type 'windows-nt)) +(defconst *acdw/at-larry* (string= (system-name) "larry")) +(defconst *acdw/at-bax* (string= (system-name) "bax")) +(defconst *acdw/at-home* (or *acdw/at-larry* *acdw/at-bax*)) + +;;;; When at work, I have to use Portable Git. +(when *acdw/at-work* + (add-to-list 'exec-path "~/bin") + (add-to-list 'exec-path "C:/Users/aduckworth/Downloads/PortableGit/bin")) + +;;; `straight.el' ~ github.com/raxod502/straight.el + +;;;; Bootstrap +;; NOTE: this doesn't work on Windows (download straight directly) +(defvar bootstrap-version) +(let ((bootstrap-file + (expand-file-name "straight/repos/straight.el/bootstrap.el" + user-emacs-directory)) + (bootstrap-version 5)) + (unless (file-exists-p bootstrap-file) + (with-current-buffer + (url-retrieve-synchronously + "https://raw.githubusercontent.com/raxod502/straight.el/develop/install.el" + 'silent 'inhibit-cookies) + (goto-char (point-max)) + (eval-print-last-sexp))) + (load bootstrap-file nil 'nomessage)) + +;;; Bootstrap `use-package' +(setq-default use-package-verbose nil + use-package-expand-minimally t + use-package-enable-imenu-support t + use-package-hook-name-suffix nil) + +(straight-use-package 'use-package) + +(setq straight-use-package-by-default t) diff --git a/init.el b/init.el index 57a2c47..4d5cb48 100644 --- a/init.el +++ b/init.el @@ -1,634 +1,752 @@ -;;; init.el ~ acdw -*- lexical-binding: t -*- - -;;; emacs configuration - general - -(use-package emacs - :demand - :init - (setq calendar-location-name "Baton Rouge, LA") - (setq calendar-latitude 30.39) - (setq calendar-longitude -91.83) - - (setq browse-url-browser-function 'browse-url-generic) - (setq browse-url-generic-program "firefox")) - -(use-package no-littering - :config - (require 'recentf) - (add-to-list 'recentf-exclude no-littering-var-directory) - (add-to-list 'recentf-exclude no-littering-etc-directory) - - (setq delete-old-versions t) - (setq kept-new-versions 6) - (setq kept-old-versions 2) - (setq version-control t) - (setq backup-directory-alist - `((".*" . ,(no-littering-expand-var-file-name "backup/")))) - - (setq auto-save-file-name-transforms - `((".*" ,(no-littering-expand-var-file-name "auto-save/") t))) - (auto-save-mode) - - (setq custom-file (no-littering-expand-etc-file-name "custom.el")) - - (setq create-lockfiles nil)) - -(use-package auth-source - :init - (setq auth-sources '("~/.authinfo")) ;; TODO: gpg - (setq user-full-name "Case Duckworth") - (setq user-mail-address "acdw@acdw.net")) - -(use-package better-defaults - :demand - :config ; add other "better defaults" of my own - (when *acdw/at-larry* - (setq visible-bell nil)) - - (auto-save-mode) - - (defun full-auto-save () - (interactive) - (save-excursion - (dolist (buf (buffer-list)) - (set-buffer buf) - (if (and (buffer-file-name) (buffer-modified-p)) - (basic-save-buffer))))) - (add-hook 'auto-save-hook 'full-auto-save) - (add-hook 'focus-out-hook 'full-auto-save) ; might be resource-intensive - - ;; follow the split! - (defun split-and-follow-below () - (interactive) - (split-window-below) - (balance-windows) - (other-window 1)) - - (defun split-and-follow-right () - (interactive) - (split-window-right) - (balance-windows) - (other-window 1)) - - (setq save-place-file (no-littering-expand-var-file-name "places")) - (save-place-mode) - - (set-language-environment "UTF-8") - (prefer-coding-system 'utf-8) - (set-default-coding-systems 'utf-8) - (set-terminal-coding-system 'utf-8) - (set-keyboard-coding-system 'utf-8) - (setq default-buffer-file-coding-system 'utf-8) - - (fset 'yes-or-no-p 'y-or-n-p) - - (global-visual-line-mode) - (mouse-avoidance-mode 'jump) - (setq show-paren-style 'mixed) - (delete-selection-mode 1) - - ;; TODO figure out how to add this to the :hook block - (add-hook 'prog-mode-hook (if (and (fboundp 'display-line-numbers-mode) - (display-graphic-p)) - #'display-line-numbers-mode - #'linum-mode)) - - (setq completion-ignore-case t) - (setq read-buffer-completion-ignore-case t) - (setq read-file-name-completion-ignore-case t) - - ;; don't confirm death - (setq confirm-kill-processes nil) - (setq confirm-kill-emacs nil) - - ;; cursor betterment - (blink-cursor-mode 0) - (setq-default cursor-type 'bar) - - :bind - ([remap split-window-below] . split-and-follow-below) - ([remap split-window-right] . split-and-follow-right) - - :hook - (prog-mode-hook . prettify-symbols-mode) - (auto-save-hook . full-auto-save) - (focus-out-hook . full-auto-save) - (before-save-hook . delete-trailing-whitespace)) - -(use-package async - :config - (dired-async-mode 1)) - -(use-package auto-compile - :config - (auto-compile-on-load-mode) - (setq load-prefer-newer t)) - -;; start the server when at home - -(if *acdw/at-home* - (server-start)) - -;;; quality-of-life improvements - -(use-package diminish) - -(use-package which-key - :diminish which-key-mode - :config - (which-key-mode)) - -(use-package recentf - :init - (setq recentf-max-menu-items 100) - (setq recentf-max-saved-items 100) - :config - (recentf-mode)) - -(use-package savehist - :config - (savehist-mode) - (setq savehist-additional-variables - '(kill-ring search-ring regexp-search-ring))) - -(use-package restart-emacs) - -(use-package volatile-highlights - :config - (volatile-highlights-mode t)) - -(use-package zop-to-char - :bind - ([remap zap-to-char] . zop-to-char) - ([remap zap-up-to-char] . zop-up-to-char)) - -(use-package easy-kill - :bind - ([remap kill-ring-save] . easy-kill) - ([remap mark-sexp] . easy-mark)) - -(use-package whole-line-or-region - :config - (whole-line-or-region-global-mode 1)) - -(use-package avy - :bind - ("M-s" . avy-goto-char-timer)) - -(use-package selectrum - :config - (ido-mode -1) ;; not sure why this is necessary - (setq enable-recursive-minibuffers t) - (minibuffer-depth-indicate-mode) - (selectrum-mode 1)) - -(use-package prescient) - -(use-package selectrum-prescient - :config - (selectrum-prescient-mode 1) - (prescient-persist-mode 1)) - -(use-package ctrlf - :config - (ctrlf-mode 1)) - -;;; programming - -(use-package aggressive-indent - :diminish aggressive-indent-mode - :hook - (prog-mode-hook . aggressive-indent-mode)) - -(use-package magit - :if *acdw/at-home* - :bind - ("C-x g" . magit)) - -(use-package forge - :if *acdw/at-home* - :after magit - :custom - (forge-owned-accounts '(("duckwork")))) - -(use-package company - :commands company-mode - :init - (setq company-idle-delay 0.1) - :hook - (prog-mode-hook . company-mode) - :bind (:map company-active-map - ("C-n" . company-select-next) - ("C-p" . company-select-previous)) - :config - (use-package company-quickhelp - :hook - (company-mode-hook . (lambda () - (company-quickhelp-local-mode))))) - -(use-package helpful - :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)) - -(when *acdw/at-home* - (use-package su - :config - (su-mode)) - - (use-package trashed - :init - (setq delete-by-moving-to-trash t))) - -(use-package smartparens - :config - (require 'smartparens-config) - (smartparens-global-mode)) - - -(use-package rainbow-mode - :hook - (prog-mode-hook . rainbow-mode)) - -;;; writing - -(use-package visual-fill-column - :init - (setq split-window-preferred-function 'visual-fill-column-split-window-sensibly) - (setq visual-fill-column-center-text t) - :config - (advice-add 'text-scale-adjust - :after #'visual-fill-column-adjust)) - -;;; window management - -(use-package switch-window - :init - (setq switch-window-shortcut-style 'qwerty) - :bind - ([remap other-window] . switch-window) - ("s-o" . switch-window)) - -;;; theming and looks - -(use-package dynamic-fonts - :init - (setq dynamic-fonts-preferred-monospace-fonts - '("Iosevka Term Slab" - "Consolas" - "Fira Code" - "DejaVu Sans Mono" - "Courier" - "Fixed")) - (setq dynamic-fonts-preferred-monospace-point-size 11) - (setq dynamic-fonts-preferred-proportional-fonts - '("DejaVu Sans" - "Georgia" - "Times New Roman" - "Times")) - (setq dynamic-fonts-preferred-proportional-point-size 12) - :config - (dynamic-fonts-setup)) - -(use-package doom-modeline - :init - (setq doom-modeline-icon nil) - (setq doom-modeline-enable-word-count t) - (when *acdw/at-larry* - (setq display-time-format "%R") - (display-time-mode)) - :hook - (after-init-hook . doom-modeline-mode)) - -(use-package ligature - :straight (ligature - :host github - :repo "mickeynp/ligature.el") - :config - (ligature-set-ligatures 'prog-mode - '("++" "--" "/=" "&&" "||" "||=" - "->" "=>" "::" "__" - "==" "===" "!=" "=/=" "!==" - "<=" ">=" "<=>" - "/*" "*/" "//" "///" - "\\n" "\\\\" - "<<" "<<<" "<<=" ">>" ">>>" ">>=" - "|=" "^=" - "**" "--" "---" "----" "-----" - "==" "===" "====" "=====" - "" "-->" "/>" - ":=" "..." ":>" ":<" ">:" "<:" - "::=" ;; add others here - )) - (global-ligature-mode t)) - -(use-package unicode-fonts - :config - (unicode-fonts-setup)) - -;; modus themes - -(use-package modus-operandi-theme - :if window-system - :config - (load-theme 'modus-operandi t t) - - (defun acdw/sunrise () - (enable-theme 'modus-operandi) - (start-process-shell-command "light" nil "light -S 60")) - - (if *acdw/at-work* - (enable-theme 'modus-operandi) - (run-at-time (nth 1 (split-string (sunrise-sunset))) - (* 60 60 24) #'acdw/sunrise))) - -(when *acdw/at-home* - (use-package modus-vivendi-theme - :if window-system - :config - (load-theme 'modus-vivendi t t) - - (defun acdw/sunset () - (enable-theme 'modus-vivendi) - (start-process-shell-command "light" nil "light -S 35")) - - (run-at-time (nth 4 (split-string (sunrise-sunset))) - (* 60 60 24) #'acdw/sunset) - (run-at-time "12am" (* 60 60 24) #'acdw/sunset))) - -;;; gemini/gopher -(use-package elpher - :straight (elpher - :repo "git://thelambdalab.xyz/elpher.git") - :bind (:map elpher-mode-map - ("n" . elpher-next-link) - ("p" . elpher-prev-link) - ("o" . elpher-follow-current-link) - ("G" . elpher-go-current)) - :hook (elpher-mode-hook . (lambda () - (variable-pitch-mode 1) - (visual-fill-column-mode 1)))) - -(use-package gemini-mode - :straight (gemini-mode - :repo "https://git.carcosa.net/jmcbray/gemini.el.git")) - -(use-package gemini-write - :straight (gemini-write - :repo "https://alexschroeder.ch/cgit/gemini-write")) - -(defun post-to-gemlog-blue (post-title user pass) - "Post current buffer to gemlog.blue." - (interactive - (let* ((title-maybe (progn ;; TODO this is ... clunky - (goto-char (point-min)) - (if (re-search-forward "^# \\(.*\\)" nil t) - (buffer-substring-no-properties - (match-beginning 1) - (match-end 1)) - ""))) - (title (read-string - (format "Title%s: " - (if (string= "" title-maybe) - "" - (concat " (" title-maybe ")"))) - nil nil title-maybe)) - (user (read-string "User: " nil)) - (pass (read-passwd "Pass: " nil))) - (list title user pass))) - - (require 'mm-url) - (let ((url-request-method "POST") - (url-request-extra-headers - '(("Content-Type" . "application/x-www-form-urlencoded"))) - (url-request-data - (mm-url-encode-www-form-urlencoded - `(("title" . ,post-title) - ("gemloguser" . ,user) - ("pw" . ,pass) - ("post" . ,(buffer-string)))))) - (with-current-buffer - (url-retrieve-synchronously "https://gemlog.blue/post.php") - (goto-char (point-min)) - (re-search-forward "\\(gemini://.*\\.gmi\\)") - (elpher-go (match-string 1))))) - -;;; exwm ~ Emacs X Window Manager -(when *acdw/at-larry* - (use-package exwm - :if window-system - :demand - :custom - (exwm-layout-show-all-buffers t) - (exwm-workspace-warp-cursor t) - ;;(mouse-autoselect-window t) - (exwm-workspace-number 4) - (exwm-input-global-keys - `( - ([remap split-window-below] . split-and-follow-below) - ([remap split-window-right] . split-and-follow-right) - ([?\s-r] . exwm-reset) - ([?\s-w] . exwm-workspace-switch) - ([?\s-&] . (lambda (command) - (interactive (list (read-shell-command "$ "))) - (start-process-shell-command command nil command))) - ,@(mapcar (lambda (i) - `(,(kbd (format "s-%d" i)) . - (lambda () - (interactive) - (exwm-workspace-switch-create ,i)))) - (number-sequence 0 9)))) - (exwm-input-simulation-keys - '(([?\C-b] . [left]) - ([?\M-b] . [C-left]) - ([?\C-f] . [right]) - ([?\M-f] . [C-right]) - ([?\C-p] . [up]) - ([?\C-n] . [down]) - ([?\C-a] . [home]) - ([?\C-e] . [end]) - ([?\M-v] . [prior]) - ([?\C-v] . [next]) - ([?\C-d] . [delete]) - ([?\C-k] . [S-end delete]) - ([?\C-s] . [?\C-f]) - ([?\C-w] . [?\C-x]) - ([?\M-w] . [?\C-c]) - ([?\C-y] . [?\C-v]))) - :hook - ((exwm-update-class-hook . - (lambda () "Rename buffer to window's class name" - (exwm-workspace-rename-buffer exwm-class-name))) - (exwm-update-title-hook . - (lambda () "Update workspace name to window title" - (when (not exwm-instance-name) - (exwm-workspace-rename-buffer exwm-title)))) - (exwm-init-hook . window-divider-mode) - (exwm-init-hook . - (lambda () "Autostart" - (start-process-shell-command "cmst" nil "cmst -m -w 5") - (start-process-shell-command "keepassxc" nil "keepassxc") - (start-process-shell-command - "pa-applet" nil - "pa-applet --disable-key-grabbing --disable-notifications") - (start-process-shell-command - "cbatticon" nil "cbatticon")))) - :config - (require 'exwm) - (exwm-enable) - (require 'exwm-systemtray) - (exwm-systemtray-enable)) - - (use-package exwm-firefox-core - :after exwm - :straight (exwm-firefox-core - :type git - :host github - :repo "walseb/exwm-firefox-core")) - - (use-package exwm-firefox - :after exwm-firefox-core - :straight (exwm-firefox - :type git - :host github - :repo "ieure/exwm-firefox") - :config - (exwm-firefox-mode)) - - (use-package exwm-mff - :straight (exwm-mff - :host github - :repo "ieure/exwm-mff" - :fork ( - :host github - :repo "duckwork/exwm-mff")) - :after exwm - :hook - (exwm-init-hook . exwm-mff-mode)) - - (use-package exwm-edit) - - ) ;; end of *acdw/at-larry* block for exwm - -;;; other applications -(use-package circe - :if *acdw/at-larry* - :init - (defun my/fetch-password (&rest params) - "Fetch a password from auth-sources" - (require 'auth-source) - (let ((match (car (apply 'auth-source-search params)))) - (if match - (let ((secret (plist-get match :secret))) - (if (functionp secret) - (funcall secret) - secret)) - (error "Password not found for %S" params)))) - - (defun my/sasl-password (nick server) - "Fetch a password for $server and $nick" - (my/fetch-password :user nick :host server)) - (require 'lui-autopaste) - (defun my/circe-prompt () - (lui-set-prompt - (concat (propertize (concat (buffer-name) ">") - 'face 'circe-prompt-face) - " "))) - (defun my/lui-setup () - (setq right-margin-width 5 - fringes-outside-margins t - word-wrap t - wrap-prefix " ") - (setf (cdr (assoc 'continuation fringe-indicator-alist)) nil)) - :hook - (circe-channel-mode-hook . enable-lui-autopaste) - (circe-chat-mode-hook . my/circe-prompt) - (lui-mode-hook . my/lui-setup) - :config - (setq circe-default-part-message "Peace out, cub scouts") - (setq circe-default-quit-message "See You Space Cowpokes ......") - (setq circe-default-realname "Case D") - (setq circe-highlight-nick-type 'all) - (setq circe-reduce-lurker-spam t) - (setq circe-format-say "{nick:-12s} {body}") - (setq circe-format-self-say "{nick:-11s}> {body}") - (setq lui-time-stamp-position 'right-margin) - (setq lui-fill-type nil) - (setq lui-time-stamp-format "%H:%M") - (setq lui-track-bar-behavior 'before-switch-to-buffer) - (setq circe-network-options - `(("Freenode" - :tls t - :port 6697 - :nick "acdw" - :sasl-username "acdw" - :sasl-password ,(my/sasl-password "acdw" "irc.freenode.net") - :channels ("#emacs" "#daydreams")) - ("Tilde.chat" - :tls t - :port 6697 - :nick "acdw" - :sasl-username "acdw" - :sasl-password ,(my/sasl-password "acdw" "irc.tilde.chat") - :channels ("#gemini" "#meta")))) - (enable-lui-track-bar) - :custom-face - (circe-my-message-face ((t (:inherit 'circe-highlight-nick-face :weight normal)))) - (circe-originator-face ((t (:weight bold)))) - (circe-prompt-face ((t (:inherit 'circe-my-message-face))))) - -;;; eshell - -(use-package eshell - :init - (defun eshell/emacs (&rest args) - "Open a file in emacs." - (if (null args) - (bury-buffer) - (mapc #'find-file - (mapcar #'expand-file-name - (eshell-flatten-list (reverse args)))))) - (defun eshell/info (&optional subject) - "Invoke `info', optionally opening Info to SUBJECT." - (require 'cl) - (let ((buf (current-buffer))) - (Info-directory) - (if (not (null subject)) - (let ((node-exists (ignore-errors (Info-menu subject)))) - (if (not node-exists) - (format "No menu item `%s' in node `(dir)Top'." - subject))))))) - -(use-package eshell-syntax-highlighting - :after esh-mode - :config - (eshell-syntax-highlighting-global-mode 1)) - -;;; org-mode -(use-package org - :init - (setq org-startup-indented t) - (setq org-src-tab-acts-natively t) - (setq org-hide-emphasis-markers t) - (setq org-fontify-done-headline t) - (setq org-hide-leading-stars t) - (setq org-pretty-entities t) - - (font-lock-add-keywords 'org-mode - '(("^ *\\([-+*]\\) " - (0 (prog1 () (compose-region (match-beginning 1) - (match-end 1) - "•")))))) - :hook - (org-mode-hook . (lambda () - (variable-pitch-mode 1) - (visual-line-mode) - (visual-fill-column-mode)))) - -(use-package org-bullets - :hook - (org-mode-hook . (lambda () (org-bullets-mode 1)))) +;;; init.el -*- lexical-binding: t; coding: utf-8; fill-column: 70 -*- + +;;; Commentary: +;; I /was/ going to convert this to org-mode, but then I found this +;; page: https://yiufung.net/post/pure-emacs-lisp-init-skeleton/, +;; which pointed out that I could use `outline-mode' (or in my case, +;; `outshine') to fold and navigate a pure-elisp `init.el'. So that's +;; what I'm doing. + +;;; Basic emacs config & built-in packages +;;;; /Really/ basic emacs config +;; I /did/ use `better-defaults', but it turns out that that package +;; is (a) short and (b) mostly overriden by other settings. +(use-package emacs + :demand ; make sure this stuff loads + :init + ;; where I am + (setq calendar-location-name "Baton Rouge, LA") + (setq calendar-latitude 30.39) + (setq calendar-longitude -91.83) + + ;; firefox is love, firefox is life + (setq browse-url-browser-function 'browse-url-firefox + browse-url-new-window-flag t + browse-url-firefox-new-window-is-tab t) + + ;; honestly not sure if this is necessary + (autoload 'zap-up-to-char "misc" + "Kill up to, but not including, ARGth occurence of CHAR." t) + + ;; show parentheses + (setq show-paren-style 'mixed) + (show-paren-mode) + + ;; always work on visual lines + (global-visual-line-mode) + + ;; make the mouse avoid where I'm typing + (mouse-avoidance-mode 'jump) + + ;; delete the selection when I start typing, like a normal editor + (delete-selection-mode) + + ;; ignore case + (setq-default completion-ignore-case t + read-buffer-completion-ignore-case t + read-file-name-completion-ignore-case t) + + ;; etc defaults + (fset 'yes-or-no-p 'y-or-n-p) + (setq-default indent-tabs-mode nil + save-interprogram-paste-before-kill t + apropos-do-all t + mouse-yank-at-point t + require-final-newline t + visible-bell (not *acdw/at-larry*) + ediff-window-setup-function 'ediff-setup-windows-plain + use-dialog-box nil + mark-even-if-inactive nil + sentence-end-double-space t) + + ;; utf-8 is now, old man + (set-charset-priority 'unicode) + (set-language-environment "UTF-8") + (set-default-coding-systems 'utf-8) + (set-terminal-coding-system 'utf-8) + (set-keyboard-coding-system 'utf-8) + (set-selection-coding-system 'utf-8) + (prefer-coding-system 'utf-8) + (setq default-buffer-file-coding-system 'utf-8 + default-process-coding-system '(utf-8-unix . utf-8-unix) + locale-coding-system 'utf-8) + + ;; don't confirm killing + (setq confirm-kill-processes nil + confirm-kill-emacs nil) + + ;; simplify the GUI + (setq default-frame-alist '((tool-bar-lines . 0) + (menu-bar-lines . 0) + (vertical-scroll-bars . nil) + (horizontal-scroll-bars . nil) + (right-divider-width . 2) + (bottom-divider-width . 2) + (left-fringe-width . 2) + (right-fringe-width . 2)) + inhibit-startup-buffer-menu t + inhibit-startup-screen t + initial-buffer-choice t + initial-scratch-message nil) + + ;; When at larry, fullscreen emacs. + (when *acdw/at-larry* + (add-to-list 'default-frame-alist '(fullscreen . maximized))) + + ;; set up the cursor + (blink-cursor-mode 0) + (setq-default cursor-type 'bar + cursor-in-non-selected-windows 'hollow) + + ;; display line numbers in `prog-mode' + (add-hook 'prog-mode-hook + (if (and (fboundp 'display-line-numbers-mode) + (display-graphic-p)) + #'display-line-numbers-mode + #'linum-mode)) + + ;; custom functions + (defun split-and-follow-below () + "Split the window below and switch to the split." + (interactive) + (split-window-below) + (balance-windows) + (other-window 1)) + + (defun split-and-follow-right () + "Split the window right and switch to the split." + (interactive) + (split-window-right) + (balance-windows) + (other-window 1)) + + (defun full-auto-save () + "Save all buffers that (a) have files associated and (b) are modified." + (interactive) + (save-excursion + (dolist (buf (buffer-list)) + (set-buffer buf) + (if (and (buffer-file-name) (buffer-modified-p)) + (basic-save-buffer))))) + + (defun kill-this-buffer () + "Kill the current buffer." + (interactive) + (kill-buffer nil)) + + :bind + ("C-x C-b" . ibuffer) + ("M-z" . zap-up-to-char) + ([remap split-window-below] . split-and-follow-below) + ([remap split-window-right] . split-and-follow-right) + ("C-x f" . find-file) + ("C-z" . nil) + ("C-x k" . kill-this-buffer) + ("C-x K" . kill-buffer) + + :hook + (prog-mode-hook . prettify-symbols-mode) + ((auto-save-hook focus-out-hook) . full-auto-save) + (before-save-hook . delete-trailing-whitespace)) + +;;;; Keep .emacs.d clean +;; load this early for other packages to use +(use-package no-littering + :demand + :config + (setq custom-file (no-littering-expand-etc-file-name "custom.el")) + + (setq create-lockfiles nil) + + (setq delete-old-versions t + kept-new-versions 6 + kept-old-versions 2 + version-control t) + + (setq backup-directory-alist + `((".*" . ,(no-littering-expand-var-file-name "backup/")))) + + (setq auto-save-file-name-transforms + `((".*" ,(no-littering-expand-var-file-name "auto-save/") t))) + (auto-save-mode)) + +;;;; Uniquily name buffers +(use-package uniquify + :straight nil + :init + (setq uniquify-buffer-name-style 'forward)) + +;;;; Use async when possible +(use-package async + :config + (dired-async-mode)) + +;;;; Autocompile elisp files (like this one) +(use-package auto-compile + :init + (setq load-prefer-newer t) + :config + (auto-compile-on-load-mode)) + +;;;; Recent files +(use-package recentf + :init + (setq recentf-max-menu-items 100 + recentf-max-saved-items 100) + :config + (add-to-list 'recentf-exclude no-littering-var-directory) + (add-to-list 'recentf-exclude no-littering-etc-directory) + (recentf-mode)) +;;;; Save places in files +(use-package saveplace + :init + (setq save-place-file (no-littering-expand-var-file-name "places")) + (when *acdw/at-work* + (setq save-place-forget-unreadable-files nil)) + :config + (save-place-mode)) + +;;;; Save history of commands, etc. +(use-package savehist + :init + (setq savehist-additional-variables + '(kill-ring + search-ring + regexp-search-ring)) + :config + (savehist-mode)) + +;;;; Authority sources for logins +;; TODO: use gpg +(use-package auth-source + :init + (setq auth-sources '("~/.authinfo")) + (setq user-full-name "Case Duckworth") + (setq user-mail-address "acdw@acdw.net")) + +;;; General-ish Packages +;;;; General improvements +;;;;; Diminish TODO: is this necessary? +(use-package diminish) + +;;;;; Restart emacs /from within/ emacs +(use-package restart-emacs) + +;;;; User interface +;;;;; Pop-up help for keys +(use-package which-key + :diminish which-key-mode + :init + (setq which-key-enable-extended-define-key t) + :config + (which-key-setup-side-window-right-bottom) + (which-key-mode)) + +;;;;; A better help buffer +(use-package helpful + :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)) + +;;;;; A better `outline-mode' +(use-package outshine + :init + (setq outshine-cycle-emulate-tab t) + :bind (:map outshine-mode-map + ("" . outshine-cycle-buffer) + ("" . outshine-cycle-buffer)) + :hook + (emacs-lisp-mode . outshine-mode)) + +;;;;; Item selection & narrowing +(use-package selectrum + :init + (setq enable-recursive-minibuffers t) + (minibuffer-depth-indicate-mode) + :config + (selectrum-mode)) + +(use-package prescient) + +(use-package selectrum-prescient + :config + (selectrum-prescient-mode) + (prescient-persist-mode)) + +;;;;; Searching +(use-package ctrlf + :config + (ctrlf-mode)) + +;;;;; Visually switch windows +(use-package switch-window + :init + (setq switch-window-shortcut-style 'qwerty) + :bind + ([remap other-window] . switch-window) + ("s-o" . switch-window)) + +;;;; Theming, looks, fonts +;;;;; Modeline +(use-package doom-modeline + :init + (setq doom-modeline-icon nil + doom-modeline-enable-word-count t) + + (when *acdw/at-larry* + (setq display-time-format "%R") + (display-time-mode)) + + :hook + (window-setup-hook . doom-modeline-mode)) +;;;;; Ligatures +(use-package ligature + :straight (ligature + :host github + :repo "mickeynp/ligature.el") + :config + (ligature-set-ligatures 'prog-mode + '("++" "--" "/=" "&&" "||" "||=" + "->" "=>" "::" "__" + "==" "===" "!=" "=/=" "!==" + "<=" ">=" "<=>" + "/*" "*/" "//" "///" + "\\n" "\\\\" + "<<" "<<<" "<<=" ">>" ">>>" ">>=" + "|=" "^=" + "**" "--" "---" "----" "-----" + "==" "===" "====" "=====" + "" "-->" "/>" + ":=" "..." ":>" ":<" ">:" "<:" + "::=" ;; add others here + )) + (global-ligature-mode)) +;;;;; Unicode +(use-package unicode-fonts + :config + (unicode-fonts-setup)) +;;;;; Modus themes +(use-package modus-operandi-theme + :if window-system + :config + (load-theme 'modus-operandi t t) + + (defun acdw/sunrise () + (enable-theme 'modus-operandi) + (start-process-shell-command "light" nil "light -S 60")) + + (if *acdw/at-work* + (enable-theme 'modus-operandi) + (run-at-time (nth 1 (split-string (sunrise-sunset))) + (* 60 60 24) #'acdw/sunrise))) + +(when *acdw/at-home* + (use-package modus-vivendi-theme + :if window-system + :config + (load-theme 'modus-vivendi t t) + + (defun acdw/sunset () + (enable-theme 'modus-vivendi) + (start-process-shell-command "light" nil "light -S 35")) + + (run-at-time (nth 4 (split-string (sunrise-sunset))) + (* 60 60 24) #'acdw/sunset) + (run-at-time "12am" (* 60 60 24) #'acdw/sunset))) +;;;; General text editing +;;;;; Jump to characters fast +(use-package avy + :bind + ("M-s" . avy-goto-char-timer)) +;;;;; Show text commands acted on +(use-package volatile-highlights + :config + (volatile-highlights-mode)) +;;;;; Visual replacement for `zap-to-char' +(use-package zop-to-char + :bind + ([remap zap-to-char] . zop-to-char) + ([remap zap-up-to-char] . zop-up-to-char)) +;;;;; Kill & mark things more visually +(use-package easy-kill + :bind + ([remap kill-ring-save] . easy-kill) + ([remap mark-sexp] . easy-mark)) +;;;;; Operate on the current line if no region is active +(use-package whole-line-or-region + :config + (whole-line-or-region-global-mode)) + +;;;;; Expand region +(use-package expand-region + :bind + ("C-=" . er/expand-region)) +;;;; Programming +;;;;; Code completion +(use-package company + :init + (setq company-idle-delay 0.1 + company-show-numbers t) + :config + (let ((map company-active-map)) + (mapc (lambda (x) + (define-key map (format "%d" x) + `(lambda () + (interactive) + (company-complete-number ,x)))) + (number-sequence 0 9))) + :hook + (prog-mode-hook . company-mode) + :bind (:map company-active-map + ("C-n" . company-select-next) + ("C-p" . company-select-previous))) + +(use-package company-quickhelp + :hook + (company-mode-hook . company-quickhelp-local-mode)) + +(use-package company-prescient + :hook + (company-mode-hook . company-prescient-mode)) + +;;;;; Git integration +(use-package magit + :if *acdw/at-home* + :bind + ("C-x g" . magit-status) + :config + (add-to-list 'magit-no-confirm 'stage-all-changes)) + +;; use libgit to speed up magit, only at home +(when (and *acdw/at-home* (executable-find "cmake")) + (use-package libgit) + + (use-package magit-libgit + :after (magit libgit)) + ) + +(use-package forge + :if *acdw/at-home* + :after magit + :config + (setq forge-owned-accounts '(("duckwork")))) +;;;;; Code formatting & display +;;;;;; Keep code properly indented +(use-package aggressive-indent + :diminish aggressive-indent-mode + :hook + (prog-mode-hook . aggressive-indent-mode)) +;;;;;; Smartly deal with pairs +(use-package smartparens + :config + (require 'smartparens-config) + (smartparens-global-mode)) +;;;;;; Show delimiters as different colors +(use-package rainbow-delimiters + :hook + (prog-mode-hook . rainbow-delimiters-mode)) +;;;;;; Show colors as they appear in the buffer +(use-package rainbow-mode + :hook + (prog-mode-hook . rainbow-mode)) +;;;; Writing +;;;;; `fill-column', but in `visual-line-mode' +(use-package visual-fill-column + :init + (setq split-window-preferred-function 'visual-fill-column-split-window-sensibly) + (setq visual-fill-column-center-text t) + :config + (advice-add 'text-scale-adjust + :after #'visual-fill-column-adjust)) + +;;;; Machine-specific +;;;;; Linux at home +(when *acdw/at-home* +;;;;;; Edit files with `sudo' (I think?) + (use-package su + :config + (su-mode)) +;;;;;; Implement XDG Trash specification + (use-package trashed + :init + (setq delete-by-moving-to-trash t)) +;;;;;; Build exec-path from $PATH + (use-package exec-path-from-shell + :demand + :config + (exec-path-from-shell-initialize)) + ) +;;; Specialized packages +;;;; Gemini & Gopher +(use-package elpher + :straight (elpher + :repo "git://thelambdalab.xyz/elpher.git") + :bind (:map elpher-mode-map + ("n" . elpher-next-link) + ("p" . elpher-prev-link) + ("o" . elpher-follow-current-link) + ("G" . elpher-go-current)) + :hook (elpher-mode-hook . (lambda () + (variable-pitch-mode) + (set-fill-column 100) + (visual-fill-column-mode)))) + +(use-package gemini-mode + :straight (gemini-mode + :repo "https://git.carcosa.net/jmcbray/gemini.el.git")) + +(use-package gemini-write + :straight (gemini-write + :repo "https://alexschroeder.ch/cgit/gemini-write")) + +(defun post-to-gemlog-blue (post-title user pass) + "Post current buffer to gemlog.blue." + (interactive + (let* ((title-maybe (progn ;; TODO this is ... clunky + (goto-char (point-min)) + (if (re-search-forward "^# \\(.*\\)" nil t) + (buffer-substring-no-properties + (match-beginning 1) + (match-end 1)) + ""))) + (title (read-string + (format "Title%s: " + (if (string= "" title-maybe) + "" + (concat " (" title-maybe ")"))) + nil nil title-maybe)) + (user (read-string "User: " nil)) + (pass (read-passwd "Pass: " nil))) + (list title user pass))) + + (require 'mm-url) + (let ((url-request-method "POST") + (url-request-extra-headers + '(("Content-Type" . "application/x-www-form-urlencoded"))) + (url-request-data + (mm-url-encode-www-form-urlencoded + `(("title" . ,post-title) + ("gemloguser" . ,user) + ("pw" . ,pass) + ("post" . ,(buffer-string)))))) + (with-current-buffer + (url-retrieve-synchronously "https://gemlog.blue/post.php") + (goto-char (point-min)) + (re-search-forward "\\(gemini://.*\\.gmi\\)") + (elpher-go (match-string 1))))) + +;;;; exwm ~ Emacs X Window Manager +(when *acdw/at-larry* + (use-package exwm + :if window-system + :demand + :custom + (exwm-layout-show-all-buffers t) + (exwm-workspace-warp-cursor t) + ;;(mouse-autoselect-window t) + (exwm-workspace-number 4) + (exwm-input-global-keys + `( + ([remap split-window-below] . split-and-follow-below) + ([remap split-window-right] . split-and-follow-right) + ([?\s-r] . exwm-reset) + ([?\s-w] . exwm-workspace-switch) + ([?\s-&] . (lambda (command) + (interactive (list (read-shell-command "$ "))) + (start-process-shell-command command nil command))) + ,@(mapcar (lambda (i) + `(,(kbd (format "s-%d" i)) . + (lambda () + (interactive) + (exwm-workspace-switch-create ,i)))) + (number-sequence 0 9)))) + (exwm-input-simulation-keys + '(([?\C-b] . [left]) + ([?\M-b] . [C-left]) + ([?\C-f] . [right]) + ([?\M-f] . [C-right]) + ([?\C-p] . [up]) + ([?\C-n] . [down]) + ([?\C-a] . [home]) + ([?\C-e] . [end]) + ([?\M-v] . [prior]) + ([?\C-v] . [next]) + ([?\C-d] . [delete]) + ([?\C-k] . [S-end delete]) + ([?\C-s] . [?\C-f]) + ([?\C-w] . [?\C-x]) + ([?\M-w] . [?\C-c]) + ([?\C-y] . [?\C-v]))) + :hook + ((exwm-update-class-hook . + (lambda () "Rename buffer to window's class name" + (exwm-workspace-rename-buffer exwm-class-name))) + (exwm-update-title-hook . + (lambda () "Update workspace name to window title" + (when (not exwm-instance-name) + (exwm-workspace-rename-buffer exwm-title)))) + (exwm-init-hook . window-divider-mode) + (exwm-init-hook . + (lambda () "Autostart" + (start-process-shell-command "cmst" nil "cmst -m -w 5") + (start-process-shell-command "keepassxc" nil "keepassxc") + (start-process-shell-command + "pa-applet" nil + "pa-applet --disable-key-grabbing --disable-notifications") + (start-process-shell-command + "cbatticon" nil "cbatticon")))) + :config + (require 'exwm) + (exwm-enable) + (require 'exwm-systemtray) + (exwm-systemtray-enable)) + + (use-package exwm-firefox-core + :after exwm + :straight (exwm-firefox-core + :type git + :host github + :repo "walseb/exwm-firefox-core")) + + (use-package exwm-firefox + :after exwm-firefox-core + :straight (exwm-firefox + :type git + :host github + :repo "ieure/exwm-firefox") + :config + (exwm-firefox-mode)) + + (use-package exwm-mff + :straight (exwm-mff + :host github + :repo "ieure/exwm-mff" + :fork ( + :host github + :repo "duckwork/exwm-mff")) + :after exwm + :hook + (exwm-init-hook . exwm-mff-mode)) + + (use-package exwm-edit) + + ) ;; end of *acdw/at-larry* block for exwm + +;;;; IRC +(use-package circe + :if *acdw/at-larry* + :init + (defun my/fetch-password (&rest params) + "Fetch a password from auth-sources" + (require 'auth-source) + (let ((match (car (apply 'auth-source-search params)))) + (if match + (let ((secret (plist-get match :secret))) + (if (functionp secret) + (funcall secret) + secret)) + (error "Password not found for %S" params)))) + + (defun my/sasl-password (nick server) + "Fetch a password for $server and $nick" + (my/fetch-password :user nick :host server)) + (require 'lui-autopaste) + (defun my/circe-prompt () + (lui-set-prompt + (concat (propertize (concat (buffer-name) ">") + 'face 'circe-prompt-face) + " "))) + (defun my/lui-setup () + (setq right-margin-width 5 + fringes-outside-margins t + word-wrap t + wrap-prefix " ") + (setf (cdr (assoc 'continuation fringe-indicator-alist)) nil)) + :hook + (circe-channel-mode-hook . enable-lui-autopaste) + (circe-chat-mode-hook . my/circe-prompt) + (lui-mode-hook . my/lui-setup) + :config + (setq circe-default-part-message "Peace out, cub scouts") + (setq circe-default-quit-message "See You Space Cowpokes ......") + (setq circe-default-realname "Case D") + (setq circe-highlight-nick-type 'all) + (setq circe-reduce-lurker-spam t) + (setq circe-format-say "{nick:-12s} {body}") + (setq circe-format-self-say "{nick:-11s}> {body}") + (setq lui-time-stamp-position 'right-margin) + (setq lui-fill-type nil) + (setq lui-time-stamp-format "%H:%M") + (setq lui-track-bar-behavior 'before-switch-to-buffer) + (setq circe-network-options + `(("Freenode" + :tls t + :port 6697 + :nick "acdw" + :sasl-username "acdw" + :sasl-password ,(my/sasl-password "acdw" "irc.freenode.net") + :channels ("#emacs" "#daydreams")) + ("Tilde.chat" + :tls t + :port 6697 + :nick "acdw" + :sasl-username "acdw" + :sasl-password ,(my/sasl-password "acdw" "irc.tilde.chat") + :channels ("#gemini" "#meta")))) + (enable-lui-track-bar) + :custom-face + (circe-my-message-face ((t (:inherit 'circe-highlight-nick-face :weight normal)))) + (circe-originator-face ((t (:weight bold)))) + (circe-prompt-face ((t (:inherit 'circe-my-message-face))))) + +;;;; eshell +(use-package eshell + :init + (defun eshell/emacs (&rest args) + "Open a file in emacs." + (if (null args) + (bury-buffer) + (mapc #'find-file + (mapcar #'expand-file-name + (eshell-flatten-list (reverse args)))))) + (defun eshell/info (&optional subject) + "Invoke `info', optionally opening Info to SUBJECT." + (require 'cl) + (let ((buf (current-buffer))) + (Info-directory) + (if (not (null subject)) + (let ((node-exists (ignore-errors (Info-menu subject)))) + (if (not node-exists) + (format "No menu item `%s' in node `(dir)Top'." + subject))))))) + +(use-package eshell-syntax-highlighting + :after esh-mode + :config + (eshell-syntax-highlighting-global-mode)) + +;;;; org-mode +(use-package org + :init + (setq org-startup-indented t) + (setq org-src-tab-acts-natively t) + (setq org-hide-emphasis-markers t) + (setq org-fontify-done-headline t) + (setq org-hide-leading-stars t) + (setq org-pretty-entities t) + + (font-lock-add-keywords 'org-mode + '(("^ *\\([-+*]\\) " + (0 (prog1 () (compose-region (match-beginning 1) + (match-end 1) + "•")))))) + :hook + (org-mode-hook . variable-pitch-mode)) + +(use-package org-bullets + :hook + (org-mode-hook . (lambda () (org-bullets-mode)))) -- cgit 1.4.1-21-gabe81