;;; ~/.emacs -*- mode: emacs-lisp; lexical-binding: t; -*- ;; Author: Case Duckworth ;; Bankruptcy: 12 ;;; Initialization -- see also ~/.emacs.d/early-init.el ;; TODO -- think about making C-q a personal leader (setopt custom-file (locate-user-emacs-file "custom.el")) (load custom-file :no-error) (add-hook 'Custom-mode-hook (lambda () (run-with-idle-timer 0.25 nil #'custom-show-all-widgets))) (defvar user-private-file (locate-user-emacs-file "private.el") "Private customizations") ;; make sure it's really private! (and (file-exists-p user-private-file) (= (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) ;; (setopt case-background "alice blue" ; alice ;; case-shadow "violet" ;; case-highlight-1 "wheat" ;; case-highlight-2 "aquamarine" ;; case-warning "brown" ;; case-mode-line-active "light goldenrod" ;; case-mode-line-inactive "light steel blue" ;; case-string "snow") (load-theme 'case :no-confirm) ; see ~/.emacs.d/case-theme.el (add-hook 'after-init-hook #'setup-faces) ;;; Basic settings ;; Auth (with-package '(keepassxc-shim :url "https://codeberg.org/acdw/keepassxc-shim.el") (keepassxc-shim-activate) (setopt auth-sources '("secrets:default")) (add-hook 'auth-info-hook #'truncate-lines-local-mode)) ;; 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 nil) ;; 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 (add-hook 'before-save-hook #'delete-trailing-whitespace-except-current-line) (setopt whitespace-style '(face trailing tabs tab-mark)) (setopt whitespace-global-modes '(not rcirc-mode jabber-chat-mode)) (global-whitespace-mode) (hide-minor-mode 'global-whitespace-mode) (with-eval-after-load 'whitespace (setf/alist whitespace-display-mappings 'tab-mark '(9 [?· 9] [?» 9] [?\\ 9]))) ;; Automatically indent buffer when saving (define-minor-mode indent-on-save-mode "Automatically re-indent the buffer on save." :lighter " >" (if indent-on-save-mode (add-hook 'before-save-hook #'fixup-whitespace nil t) (remove-hook 'before-save-hook #'fixup-whitespace t))) (add-hook 'prog-mode-hook #'indent-on-save-mode) (remove-hook 'makefile-mode-hook #'indent-on-save-mode) ; makefiles is dumb (add-hook 'prog-mode-hook #'display-fill-column-indicator-mode) ;; Comments (setopt comment-column 0) (setopt comment-indent-offset 1) ;;; Efficiency ... ? (setopt load-prefer-newer t) (setopt read-process-output-max (* 512 1024)) (when (and (featurep 'native-compile) (fboundp 'native-comp-available-p) (native-comp-available-p)) (setopt native-comp-jit-compilation t) (setopt package-native-compile t) (setopt native-comp-async-report-warnings-errors 'silent) (setopt native-comp-warning-on-missing-source nil)) (setopt byte-compile-warnings nil) (setopt byte-compile-verbose nil) ;;; UI stuff (setopt cursor-type 'bar) (setopt cursor-in-non-selected-windows nil) (setopt highlight-nonselected-windows nil) (hide-minor-mode 'buffer-face-mode) (setopt tab-bar-show 1) (with-package 'valign ; needed for variable-pitch org-mode (add-hook 'org-mode-hook #'valign-mode) (setopt valign-fancy-bar t)) ;;; Mode line (setopt mode-line-position-line-format '("%l")) (setopt mode-line-position-column-line-format '("%l:%c")) (package-ensure 'minions) (defvar mode-line-major-mode-keymap* (let ((map (make-sparse-keymap))) (bindings--define-key map [mode-line down-mouse-1] `(menu-item "Menu Bar" ignore :filter ,(lambda (_) (mouse-menu-major-mode-map)))) (define-key map [mode-line mouse-2] #'describe-mode) (define-key map [mode-line mouse-3] #'minions-minor-modes-menu) map) "Keymap to display on major mode.") (defun make-mode-line-mode-disabler (lighter help mode) (propertize lighter 'help-echo (concat help "\n1:cancel") 'face 'italic 'mouse-face 'mode-line-highlight 'local-map (make-mode-line-mouse-map 'mouse-1 (lambda (ev) (interactive "e") (with-selected-window (posn-window (event-start ev)) (funcall mode -1) (force-mode-line-update)))))) (setopt mode-line-format `("%e" mode-line-front-space (:propertize ("" mode-line-modified mode-line-remote) display (min-width (5.0))) " %[" mode-line-buffer-identification " %]" (vc-mode (" [" vc-mode "]")) " ( " (:propertize ("" mode-name) help-echo "Major mode\n1:menu\n2:help\n3:minor" mouse-face mode-line-highlight local-map ,mode-line-major-mode-keymap*) (auto-fill-function ,(make-mode-line-mode-disabler "-f" "Auto-filling" #'auto-fill-mode)) (visual-line-mode ,(make-mode-line-mode-disabler "-v" "Visual lines" #'visual-line-mode)) (truncate-lines-local-mode ,(make-mode-line-mode-disabler "-t" "Truncating lines" #'truncate-lines-local-mode)) " " (defining-kbd-macro (:propertize "🔴" help-echo "Defining kbd macro")) (isearch-mode (:propertize "🔍" help-echo "Searching")) (overwrite-mode ,(make-mode-line-mode-disabler "✒️" "Overwriting" #'overwrite-mode)) (debug-on-error ,(make-mode-line-mode-disabler "‼️" "Debug on error" (lambda (_) (setq debug-on-error nil)))) (debug-on-quit ,(make-mode-line-mode-disabler "🚫" "Debug on quit" (lambda (_) (setq debug-on-quit nil)))) ") " (text-scale-mode text-scale-mode-lighter) (mode-line-process (" " mode-line-process " ")) " " (:propertize (line-number-mode (column-number-mode (:propertize "%l/%c" help-echo "Line/column") (:propertize "%l" help-echo "Line")) (column-number-mode (:propertize "/%c" help-echo "Column") "")) display (min-width (5.0))) (:propertize (" [" (-3 "%o") "]") help-echo "Position in buffer" display (min-width (6.0))) ,(propertize "%n" 'help-echo "Narrowed\n1:widen" 'mouse-face 'mode-line-highlight 'local-map (make-mode-line-mouse-map 'mouse-1 #'mode-line-widen)) ("" global-mode-string))) ;;; 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) (setf/alist display-buffer-alist "\\`\\*Completions\\*\\'" '(nil (window-parameters (mode-line-format . " --- %b")))) (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) (keymap-set completion-list-mode-map "C-g" #'quit-window) ; is this a good idea? ;; Corfu (with-package 'corfu (require 'corfu) (setopt corfu-cycle t) (global-corfu-mode)) ;;; Minibuffer (setopt enable-recursive-minibuffers t) (setopt minibuffer-default-prompt-format " [%s]") (minibuffer-depth-indicate-mode) (minibuffer-electric-default-mode) (setopt minibuffer-prompt-properties '( read-only t cursor-intangible t face minibuffer-prompt)) (add-hook 'minibuffer-setup-hook #'cursor-intangible-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) (setopt savehist-additional-variables '(kill-ring command-history set-variable-value-history custom-variable-history query-replace-history read-expression-history minibuffer-history read-char-history face-name-history bookmark-history file-name-history)) (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) (with-package '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)) (with-package 'adaptive-wrap (add-hook 'visual-line-mode-hook #'adaptive-wrap-prefix-mode) (add-hook 'gemtext-mode-hook #'adaptive-wrap-prefix-mode)) ;;; Completing-read and friends ;; Consult (with-package '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-.")) (define-advice completing-read-multiple (:filter-args (args) indicator) (cons (format "[CRM%s] %s" (replace-regexp-in-string "\\`\\[.*?]\\*\\|\\[.*?]\\*\\'" "" crm-separator) (car args)) (cdr args))) ;; Marginalia (with-package 'marginalia (marginalia-mode)) ;; Embark (with-package 'embark (package-ensure 'embark-consult) (keymap-global-set "M-." #'embark-dwim) (keymap-global-set "C-." #'embark-act) (keymap-global-set "C-h B" #'embark-bindings) (add-to-list 'display-buffer-alist '("\\`\\*Embark Collect \\(Live\\|Completions\\)\\*" nil (window-parameters (mode-line-format . none)))) (add-hook 'embark-collect-mode #'consult-preview-at-point-mode) (setopt embark-indicators '(embark-mixed-indicator embark-highlight-indicator embark-isearch-highlight-indicator))) ;;; 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 require-final-newline t) (setopt view-read-only t) (setopt save-silently t) (setopt delete-by-moving-to-trash t) (setopt auto-save-default t) (setopt auto-save-no-message t) (setopt auto-save-interval 30) (setopt auto-save-timeout 5) (setopt auto-save-visited-interval 5) (setopt remote-file-name-inhibit-auto-save t) (setopt remote-file-name-inhibit-auto-save-visited t) (let ((auto-save-dir (locate-user-emacs-file "auto-save/"))) (unless (file-exists-p auto-save-dir) (make-directory auto-save-dir t)) (add-to-list 'auto-save-file-name-transforms `(".*" ,auto-save-dir t))) (auto-save-visited-mode) (add-hook 'window-selection-change-functions (defun save-old-selected-window-buffer (frame) (with-current-buffer (window-buffer (frame-old-selected-window)) (when (and (buffer-file-name) (buffer-modified-p)) (save-buffer))))) (add-hook 'buffer-list-update-hook (defun save-other-buffer () (with-current-buffer (other-buffer) (when (and (buffer-file-name) (buffer-modified-p)) (save-buffer))))) (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) (setopt uniquify-after-kill-buffer-p t) (setopt uniquify-ignore-buffers-re "^\\*") ;; Persistent undo (with-package '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 nil) (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))) (with-package 'isearch-mb (require 'isearch-mb) (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) ;;; Keybindings (repeat-mode) ;; Separate C- and control keys from halcyon ascii days ;; (define-key input-decode-map [?\C-i] [C-i]) ;; (define-key input-decode-map [?\C-m] [C-m]) ;; Modified default keybindings (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-x C-c" #'save-buffers-kill*) (keymap-global-set "C-g" #'keyboard-quit*) (keymap-global-set "C-M-\\" #'fixup-whitespace) ;; New bindings for existing stuff (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) ;; Prefix maps (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 theme (locate-user-emacs-file "case-theme.el")) "x" (find-user-file exwm (expand-file-name "~/.exwm")) "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 "o" #'overwrite-mode "f" #'auto-fill-mode)) (keymap-global-set "M-c" (define-keymap :prefix 'case-map "M-u" #'upcase-dwim "u" #'upcase-dwim "M-c" #'capitalize-dwim "c" #'capitalize-dwim "M-l" #'downcase-dwim "l" #'downcase-dwim)) (put 'upcase-dwim 'repeat-map 'case-map) (put 'capitalize-dwim 'repeat-map 'case-map) (put 'downcase-dwim 'repeat-map 'case-map) ;;; Un-keybinds ;; Why do I want to zoom with the mouse? (keymap-global-unset "C-" t) (keymap-global-unset "C-" t) ;; These are ripe for re-binding (keymap-global-unset "C-\\" t) (keymap-global-unset "M-l" t) (keymap-global-unset "" t) ;; Key settings (setopt set-mark-command-repeat-pop t) ;;; Text-editing packages ;; Hungry delete (with-package 'hungry-delete (setopt hungry-delete-chars-to-skip " \t") (with-eval-after-load 'hungry-delete (dolist (m '( eshell-mode eww-mode special-mode jabber-chat-mode)) (add-to-list 'hungry-delete-except-modes m))) (global-hungry-delete-mode)) ;;; Writing (add-hook 'text-mode-hook #'visual-line-mode) (setopt dictionary-server "dict.org") (setopt dictionary-use-single-buffer t) ;;; 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)))) (setf/alist auto-mode-alist "\\`ok\\'" #'sh-mode) ;; Eldoc (setopt eldoc-documentation-strategy #'eldoc-documentation-compose-eagerly) ;; 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 (^local-unhook 'write-file-functions 'makefile-warn-suspicious-lines)) (add-hook 'makefile-mode-hook (^local-unhook 'write-file-functions 'makefile-warn-continuations)) ;; 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 (with-package '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)) ;; Lisp (with-package 'sly (setopt inferior-lisp-program (executable-find "sbcl")) (setopt sly-command-switch-to-existing-lisp 'ask) ; oof (setopt sly-lisp-implementations `((sbcl ("sbcl" "--dynamic-space-size" "2000") :coding-system utf-8-unix))) (after sly-completion ; Follow my other completion setup (sly-symbol-completion-mode -1) (setf sly-complete-symbol-function #'sly-flex-completions) (keymap-set sly--completion-transient-mode-map "TAB" #'sly-next-completion) (keymap-set sly--completion-transient-mode-map "" #'sly-prev-completion)) (add-hook 'lisp-mode-hook #'sly-mode) ;; (add-hook 'sly-mode-hook #'corfu-mode t) (add-hook 'sly-mrepl-mode-hook #'electric-pair-mode) ;; Misc. integration (load "/home/acdw/.quicklisp/clhs-use-local.el" t) (put 'define-package 'sly-common-lisp-indent-function 1) (put 'define-glossary-term 'sly-common-lisp-indent-function 2) ;; Sly contribs (add-to-list 'sly-contribs 'sly-mrepl) (package-ensure 'sly-repl-ansi-color) (add-to-list 'sly-contribs 'sly-repl-ansi-color t) (package-ensure 'sly-asdf) (add-to-list 'sly-contribs 'sly-asdf t) (package-ensure 'sly-macrostep) (add-to-list 'sly-contribs 'sly-macrostep t) (package-ensure 'sly-quicklisp) (add-to-list 'sly-contribs 'sly-quicklisp t) (require 'sly-autoloads) (defvar sly-mrepl-previous-buffer nil "The buffer visited before sly-mrepl.") (defun sly-mrepl* () (interactive) (if (bound-and-true-p sly-buffer-connection) (if sly-mrepl-previous-buffer (switch-to-buffer-other-window sly-mrepl-previous-buffer) (other-window)) (progn (setq sly-mrepl-previous-buffer (current-buffer)) (if (bound-and-true-p sly-net-processes) (sly-mrepl #'switch-to-buffer-other-window) (sly))))) (keymap-set lisp-mode-map "C-c C-z" #'sly-mrepl*) (after sly-mode-hook (keymap-set sly-mode-map "C-c C-z" #'sly-mrepl*) (keymap-unset sly-mode-map "C-c i" t) (keymap-set sly-mode-map "C-c C-i" #'sly-import-symbol-at-point))) (require 'autoinsert) (setf/alist auto-insert-alist '("\\.asd\\'" . "ASDF System Definition") '(nil "(asdf:defsystem #:" (file-name-sans-extension (file-name-base buffer-file-name)) \n ":description \"\"" \n ":author \"" user-full-name "\"" \n ":license \"none\"" \n ":version \"0.0.1\"" \n ":depends-on ()" \n ":components (()))")) (setf/alist auto-insert-alist '("\\.lisp\\'" . "Lisp package file") (lambda () (let ((name (format ":%s" (file-name-sans-extension (file-name-base (buffer-file-name)))))) (insert "(in-package :cl-user)\n") (insert "(defpackage " name "\n") (insert " (:use :cl)\n") (insert " (:export))\n") (insert "(in-package " name ")") (newline 2)))) ;;; Forth (with-package 'forth-mode (defun forth-switch* () (interactive) (if forth-interaction-buffer (forth-switch-to-output-buffer) (run-forth))) (after forth-mode (keymap-set forth-mode-map "C-c C-c" #'forth-eval-defun) (advice-add #'forth-eval-region :after #'pulse@eval))) ;;; VC (keymap-global-set "C-x m" #'project-vc-dir) ;; Fossil (package-ensure 'vc-fossil) ;;; Compilation (setopt compilation-always-kill t) (setopt compilation-ask-about-save nil) ;;; Languages (package-ensure 'gemtext-mode) (package-ensure 'markdown-mode) ;;; Miscellaneous ;; Settings (add-hook 'after-save-hook #'executable-make-buffer-file-executable-if-script-p) (add-hook 'messages-buffer-mode-hook (^turn-off 'display-fill-column-indicator-mode)) (add-hook 'prog-mode-hook #'auto-fill-mode) (add-hook 'prog-mode-hook #'electric-pair-local-mode) (context-menu-mode) (delete-selection-mode) (global-goto-address-mode) (global-so-long-mode) (pixel-scroll-precision-mode) (setopt bookmark-save-flag 1) (setopt disabled-command-function nil) (setopt display-fill-column-indicator-character ?·) (setopt electric-pair-skip-whitespace 'chomp) (setopt eval-expression-print-length nil) (setopt eval-expression-print-level nil) (setopt fill-column 80) (setopt finger-X.500-host-regexps '(".*tilde.*")) (setopt help-window-keep-selected t) (setopt help-window-select t) (setopt read-extended-command-predicate #'command-completion-default-include-p) (setopt recenter-positions '(top middle bottom)) (setopt save-interprogram-paste-before-kill t) (setopt scroll-conservatively 101) (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) (setopt switch-to-buffer-obey-display-actions t) (setopt tmm-completion-prompt nil) (setopt tmm-mid-prompt " -- ") (setopt x-underline-at-descent-line t) (show-paren-mode) (tooltip-mode -1) ;; Advice & Hooks (define-advice canonically-space-region (:around (orig &rest args) double-space-sentences) "Always double-space sentences canonically." (let ((sentence-end-double-space t)) (apply orig args))) (define-advice switch-to-buffer (:after (&rest _) normal-mode) "Automatically determine the mode for non-file buffers." (when-let ((_ (and (eq major-mode 'fundamental-mode) (not buffer-file-name))) (buffer-file-name (buffer-name))) (normal-mode))) (add-hook 'special-mode-hook (defun hl-line@special-mode () (unless (derived-mode-p 'help-mode ; add other modes here 'Info-mode 'Man-mode 'eww-mode 'elpher-mode) (hl-line-mode)))) (add-hook 'dired-mode-hook #'hl-line-mode) ;;; Jabber ;; (package-ensure 'jabber) ;; (autoload 'jabber-global-keymap "jabber" nil t 'keymap) ;; (keymap-global-set "C-c j" jabber-global-keymap) ;; (keymap-set jabber-global-keymap "c" #'jabber-connect-all) ;; (after jabber ;; (require 'jabber-httpupload nil t) ;; ;; I wish jabber.el didn't clobber C-x C-j ... ;; (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)) ;; (keymap-global-set "C-x C-j" #'dired-jump) ;; (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>") ;; (defun esc/mls (str) ; escape-mode-line-string ;; (string-replace "%" "%%" str)) ;; (setopt jabber-chat-header-line-format ;; '(" " (:eval (esc/mls (jabber-jid-displayname jabber-chatting-with))) ;; " :: " (:eval (esc/mls (jabber-fix-status ;; (get (jabber-jid-symbol jabber-chatting-with) ;; 'status)))) ;; " :: " (:eval (esc/mls jabber-events-message)) ;see jabber-events.el ;; " :: " (:eval (esc/mls jabber-chatstates-message)))) ;; (setopt jabber-muc-header-line-format ;; '(" " (:eval (esc/mls (jabber-jid-displayname jabber-group))) ;; " :: " (:eval (esc/mls jabber-muc-topic)))) ;; (setopt jabber-muc-private-header-line-format ;; '(" " (:eval (esc/mls (jabber-jid-resource jabber-chatting-with))) ;; " in " (:eval (esc/mls (jabber-jid-displayname ;; (jabber-jid-user jabber-chatting-with)))) ;; " :: " (:eval (esc/mls jabber-events-message)) ;; " :: " (:eval (esc/mls jabber-chatstates-message)))) ;; (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 cookie-file (expand-file-name "oblique.txt" (car (process-lines "xdg-user-dir" "DOCUMENTS")))) (setopt eshell-banner-message (format "%s\n" (cookie cookie-file))) (setopt eshell-prompt-function (defun @eshell-prompt () (let ((rootp (zerop (user-uid)))) (concat "( " (unless (= 0 eshell-last-command-status) (format "*%d " eshell-last-command-status)) (abbreviate-file-name (eshell/pwd)) (if rootp ":root" "") " ) ")))) (setopt eshell-prompt-regexp "^(.*) ") (setopt eshell-destroy-buffer-when-process-dies t) (setopt eshell-error-if-no-glob t) ;; (setopt eshell-hist-ignoredups 'erase) (setopt eshell-kill-on-exit t) (setopt eshell-prefer-lisp-functions t) (setopt eshell-prefer-lisp-variables t) (setopt eshell-scroll-to-bottom-on-input 'this) ;; (setopt eshell-history-size 1024) (keymap-global-set "C-z" #'popup-eshell) (keymap-global-set "C-c C-z" #'popup-eshell) (add-hook 'eshell-first-time-mode-hook (defun @eshell-once () (keymap-set eshell-mode-map "C-z" #'quit-window))) (add-hook 'eshell-mode-hook (defun @eshell-fix-completion () ; No idea why this is necessary (kill-local-variable 'completion-ignore-case))) ;; Eat (with-package 'eat (add-hook 'eshell-mode-hook #'eat-eshell-mode)) ;;; Browsing ;; Dired (files) (add-hook 'dired-mode-hook #'dired-hide-details-mode) (add-hook 'dired-mode-hook #'truncate-lines-local-mode) (setopt dired-auto-revert-buffer t) (setopt dired-clean-confirm-killing-deleted-buffers nil) (setopt dired-create-destination-dirs 'always) (setopt dired-do-revert-buffer t) (setopt dired-dwim-target t) (setopt dired-hide-details-hide-symlink-targets nil) (setopt dired-listing-switches "-AlFhv --group-directories-first") (setopt dired-ls-F-marks-symlinks t) (setopt dired-no-confirm '(byte-compile load chgrp chmod chown copy move hardlink symlink shell touch)) (setopt dired-recursive-copies 'always) (setopt dired-recursive-deletes 'always) (after dired (require 'dired-x) (setopt dired-omit-files (regexp-concat dired-omit-files ;; "^\\..+$" ; hidden files ;; CHICKEN ... this may be overkill "\\.s?o$" "\\.import\\.scm$" "\\.\\(build\\|install\\)\\.sh$" "\\.link$")) (keymap-set dired-mode-map "C-j" #'dired-up-directory) (keymap-set dired-mode-map ")" #'dired-omit-mode)) (with-package 'dired-subtree (after dired (keymap-set dired-mode-map "i" #'dired-subtree-toggle))) (with-package 'dired-hide-dotfiles (after dired (keymap-set dired-mode-map "." #'dired-hide-dotfiles-mode))) ;; Elpher (gemini/gopher) (with-package 'elpher (after elpher ;; Try to emulate eww bindings if possible (keymap-set elpher-mode-map "l" #'elpher-back) (keymap-set elpher-mode-map "g" #'elpher-reload) (keymap-set elpher-mode-map "G" #'elpher-go) (keymap-set elpher-mode-map "v" #'elpher-view-raw) (keymap-set elpher-mode-map "E" #'elpher-set-gopher-coding-system))) ;;; HTTP browsing ;; Eww / Shr (setopt shr-max-width nil) ; covered in hook below (setopt shr-max-image-proportion 0.9) (setopt shr-discard-aria-hidden t) (setopt eww-auto-rename-buffer (defun title+url () (when (eq major-mode 'eww-mode) (let ((title (plist-get eww-data :title)) (url (plist-get eww-data :url))) (cond ((and title url) (format "*eww: %s :: %s" title url)) ((or title url) (format "*eww: %s") (or title url))))))) (add-hook 'eww-after-render-hook (defun eww@visual-line () (visual-fill-column-mode) (eww-reload t))) (with-eval-after-load 'eww (setopt eww-use-browse-url ".") (keymap-set eww-mode-map "B" #'bookmark-jump) (keymap-set eww-mode-map "b" #'bookmark-set) (keymap-unset eww-mode-map "M-n" t) (keymap-unset eww-mode-map "M-p" t)) ;; Browse-url (setopt browse-url-browser-function #'eww-browse-url) (setopt browse-url-firefox-program (executable-find "librewolf")) (setopt browse-url-firefox-arguments '("--new-tab")) (setopt browse-url-firefox-new-window-is-tab t) (setopt browse-url-generic-program (executable-find "dillo")) (setopt browse-url-generic-args nil) (setopt browse-url-secondary-browser-function #'browse-url-firefox) (with-package 'link-hint (keymap-global-set "M-l" (define-keymap :prefix 'link-map "M-l" #'link-hint-open-link "l" #'link-hint-open-link "M-w" #'link-hint-copy-link "w" #'link-hint-copy-link)) ;; With link-hint we get avy "for free" (keymap-global-set "M-j" #'avy-goto-char-timer) (setopt avy-keys '(?1 ?2 ?3 ?4 ?5 ?6 ?7 ?8 ?9))) ;; PDFs (with-package 'pdf-tools (pdf-loader-install)) (defun add-hooks (hook &rest funs) ; TESTING (declare (indent 1)) (dolist (fun funs) (add-hook hook fun))) ;; EPUBs (when (libxml-available-p) (with-package 'nov (add-to-list 'auto-mode-alist '("\\.epub\\'" . nov-mode)) (setopt nov-text-width t) (add-hooks 'nov-mode-hook (^turn-off #'whitespace-mode) (^turn-off #'hl-line-mode) #'visual-line-mode #'visual-fill-column-mode #'variable-pitch-mode))) ;;; EXWM (setf/alist display-buffer-alist shell-command-buffer-name-async '(display-buffer-no-window)) (when (and (getenv "DISPLAY") (getenv "IN_EXWM")) (package-ensure 'exwm t) (load (expand-file-name "~/.exwm"))) ;;; Emacs everywhere (if (cl-every #'executable-find '("xclip" "xdotool" "xprop" "xwininfo")) (with-package 'emacs-everywhere (setopt emacs-everywhere-frame-parameter '((name . "emacs-everywhere") (fullscreen . nil) (width . 80) (height . 24))) (setopt emacs-everywhere-top-padding nil)) (defalias #'emacs-everywhere #'ignore)) ;;; Lua (with-package 'lua-mode (setopt lua-indent-level 4) (add-hook 'lua-mode-hook (^turn-off #'indent-tabs-mode))) ;;; Fish (package-ensure 'fish-mode) ;;; Go (with-package 'go-mode)