emacs/init.el

1040 lines
32 KiB
EmacsLisp
Raw Normal View History

2021-02-26 17:31:50 +00:00
;;; init.el -*- lexical-binding: t; coding: utf-8 -*-
2021-03-01 05:58:57 +00:00
;; Copyright (C) 2020-2021 Case Duckworth
;;
2021-02-26 17:31:50 +00:00
;; Author: Case Duckworth <acdw@acdw.net>
2021-03-01 05:58:57 +00:00
;; Created: Sometime during Covid-19, 2020
2021-02-26 17:31:50 +00:00
;; Keywords: configuration
2021-03-01 05:58:57 +00:00
;; URL https://tildegit.org/acdw/emacs
;;
;; This file is NOT part of GNU Emacs.
;;
;;; License:
;;
;; Everyone is permitted to do whatever with this software, without
;; limitation. This software comes without any warranty whatsoever,
;; but with two pieces of advice:
;; - Don't hurt yourself.
;; - Make good choices.
;;
;;; Comentary:
;;
2021-03-04 23:37:17 +00:00
;;; Research:
;; (map! :leader (:prefix "w" :desc "Toggle full screen buffer" "f"
;; #'toggle-maximize-buffer))
;;
2021-03-01 05:58:57 +00:00
;;; Code:
2021-02-26 17:31:50 +00:00
2021-03-01 05:58:57 +00:00
;; User information
(setq user-full-name "Case Duckworth"
user-mail-address "acdw@acdw.net"
calendar-location-name "Baton Rouge, LA"
calendar-latitude 30.4
calendar-longitude -91.1
2021-03-01 20:44:43 +00:00
calendar-date-style 'iso
custom-file (expand-file-name "custom.el" acdw/etc-dir))
2021-02-26 17:31:50 +00:00
2021-03-01 05:58:57 +00:00
;; Load newer files first
(setq-default load-prefer-newer t)
2021-02-26 17:31:50 +00:00
2021-03-01 20:44:43 +00:00
;; No littering
(use-package no-littering
:demand
:init (setq no-littering-etc-directory acdw/etc-dir
no-littering-var-directory acdw/var-dir))
2021-02-26 17:31:50 +00:00
2021-03-01 05:58:57 +00:00
(defun when-unfocused (func &rest args)
"Run FUNC with ARGS iff all frames are out of focus."
(when (seq-every-p #'null (mapcar #'frame-focus-state (frame-list)))
(apply func args)))
2021-03-01 20:44:43 +00:00
(define-minor-mode acdw/reading-mode
"Make reading comfier."
:lighter " Read"
(if acdw/reading-mode
(progn ;; turn on
2021-03-01 22:57:55 +00:00
;; (text-scale-increase +1)
2021-03-01 20:44:43 +00:00
(display-fill-column-indicator-mode -1)
2021-03-01 22:57:55 +00:00
(setq cursor-type 'hbar)
2021-03-01 20:44:43 +00:00
(dolist (func '(visual-fill-column-mode
iscroll-mode))
(when (fboundp func)
(funcall func +1))))
(progn ;; turn off
2021-03-01 22:57:55 +00:00
;; (text-scale-increase 0)
(setq cursor-type 'bar)
2021-03-01 20:44:43 +00:00
(display-fill-column-indicator-mode +1)
(dolist (func '(visual-fill-column-mode
iscroll-mode))
(when (fboundp func)
(funcall func -1))))))
2021-03-01 22:57:55 +00:00
(defun hook--read-only-cursor ()
(setq cursor-type (if buffer-read-only 'hbar 'bar)))
(add-hook 'read-only-mode-hook #'hook--read-only-cursor)
2021-03-01 05:58:57 +00:00
;; Dialogs & alerts
(setq-default use-dialog-box nil) ; Don't use a dialog box
(fset 'yes-or-no-p #'y-or-n-p)
(defun flash-mode-line ()
(ding)
(invert-face 'mode-line)
(run-with-timer 0.2 nil #'invert-face 'mode-line))
(setq-default visible-bell nil ; Don't use a visible bell
ring-bell-function #'flash-mode-line)
(defun hook--gc-when-unfocused ()
(when-unfocused #'garbage-collect))
(add-function :after after-focus-change-function
#'hook--gc-when-unfocused)
;; Minibuffer
(setq-default
minibuffer-prompt-properties '(read-only t
2021-03-01 18:13:28 +00:00
cursor-intangible t
face minibuffer-prompt)
2021-03-01 05:58:57 +00:00
enable-recursive-minibuffers t
file-name-shadow-properties '(invisible t))
(file-name-shadow-mode +1)
(minibuffer-depth-indicate-mode +1)
(use-package savehist
2021-03-01 18:13:28 +00:00
:straight nil
:init
(setq-default
savehist-file (expand-file-name "history" acdw/var-dir)
savehist-additional-variables '(kill-ring search-ring regexp-search-ring)
history-length t
history-delete-duplicates t
savehist-autosave-interval 60)
:config (savehist-mode +1))
2021-03-01 05:58:57 +00:00
;; Backups
(setq-default backup-by-copying t
delete-old-versions -1 ; Don't delete old versions
version-control t ; Make numeric backups
vc-make-backup-files t ; Backup version-controlled files
)
(let ((dir (expand-file-name "backup" acdw/var-dir)))
(make-directory dir 'parents)
(setq-default backup-directory-alist
`((".*" . ,dir))))
;; Lockfiles
(setq-default create-lockfiles nil) ; Are these necessary?
;; Autosaves
2021-03-01 18:13:28 +00:00
(setq auto-save-default nil ; Don't use `auto-save' system
)
2021-03-01 05:58:57 +00:00
(use-package super-save
2021-03-01 18:13:28 +00:00
:defer 5 ; This package can wait
:init
(setq-default
super-save-remote-files nil ; Don't save remote files
super-save-exclude '(".gpg") ; Wouldn't work anyway
super-save-auto-save-when-idle t)
:config
(super-save-mode +1))
2021-03-01 05:58:57 +00:00
;; Auto-revert
(global-auto-revert-mode +1) ; Automatically revert a file
; to its on-disk contents
(use-package saveplace
2021-03-01 18:13:28 +00:00
:straight nil
:init
(setq-default
save-place-file (expand-file-name "places" acdw/var-dir)
save-place-forget-unreadable-files (eq acdw/system :home))
:config (save-place-mode +1))
2021-03-01 05:58:57 +00:00
(use-package recentf
2021-03-01 18:13:28 +00:00
:straight nil
:init
(setq recentf-save-file (expand-file-name "recentf" acdw/var-dir)
recentf-max-menu-items 100
recentf-max-saved-items nil
recentf-auto-cleanup 'never)
(defun maybe-save-recentf ()
"Save `recentf-file' every five minutes, but only when out of focus."
(defvar recentf--last-save (time-convert nil 'integer)
"When we last saved the `recentf-save-list'.")
(when (> (time-convert (time-since recentf--last-save) 'integer)
(* 60 5))
(setq-default recentf--last-save (time-convert nil 'integer))
(when-unfocused #'recentf-save-list)))
:config
(recentf-mode +1)
(add-to-list 'recentf-exclude acdw/var-dir)
(add-to-list 'recentf-exclude acdw/etc-dir)
(add-function :after after-focus-change-function
#'maybe-save-recentf))
2021-03-01 05:58:57 +00:00
;; Uniquify
(use-package uniquify
2021-03-01 18:13:28 +00:00
:straight nil
:init
(setq-default
uniquify-buffer-name-style 'forward ; bubble 'up' the directory tree
uniquify-separator "/" ; separate path elements
uniquify-after-kill-buffer-p t ; hook into buffer kills
uniquify-ignore-buffers-re "^\\*" ; don't worry about special buffers
))
2021-03-01 05:58:57 +00:00
;; Scratch
(setq-default
inhibit-startup-screen t ; Don't show the splash screen
initial-buffer-choice t ; Start on *scratch*
initial-scratch-message
(concat ";; Howdy, "
(nth 0 (split-string user-full-name)) "!"
" Welcome to GNU Emacs.\n\n"))
(defun immortal-scratch ()
"Don't kill *scratch* when asked to by `kill-buffer'."
(if (not (eq (current-buffer) (get-buffer "*scratch*")))
t
(bury-buffer)
nil))
(add-hook 'kill-buffer-query-functions #'immortal-scratch)
;; Easier buffer-killing
(defun kill-a-buffer (&optional prefix)
"Kill a buffer and its window, prompting only on unsaved changes.
`kill-a-buffer' uses the PREFIX argument to determine which buffer(s) to kill:
0 => Kill THIS buffer & window
4 (C-u) => Kill OTHER buffer & window
16 (C-u C-u) => Run the default `kill-buffer'."
(interactive "P")
(pcase (or (car prefix) 0)
(0 (kill-current-buffer)
(unless (one-window-p) (delete-window)))
(4 (other-window 1)
(kill-current-buffer)
(unless (one-window-p) (delete-window)))
(16 (let ((current-prefix-arg nil))
(kill-buffer)))))
(bind-key "C-x k" #'kill-a-buffer)
;; UTF-8 with LF line endings
(set-charset-priority 'unicode)
(set-language-environment "UTF-8")
(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)
(set-selection-coding-system 'utf-8-unix)
(setq-default
locale-coding-system 'utf-8-unix
coding-system-for-read 'utf-8-unix
coding-system-for-write 'utf-8-unix
buffer-file-coding-system 'utf-8-unix
org-export-coding-system 'utf-8-unix
org-html-coding-system 'utf-8-unix ; doesn't take from above
default-process-coding-system '(utf-8-unix . utf-8-unix)
x-select-request-type '(UTF8_STRING COMPOUND_TEXT TEXT STRING))
(defun ewiki/no-junk-please-were-unixish ()
"Convert line endings to UNIX, dammit."
(let ((coding-str (symbol-name buffer-file-coding-system)))
(when (string-match "-\\(?:dos\\|mac\\)$" coding-str)
(set-buffer-file-coding-system 'unix))))
(add-hook 'find-file-hook #'ewiki/no-junk-please-were-unixish)
(add-hook 'before-save-hook #'ewiki/no-junk-please-were-unixish)
;; Cursor
(setq-default cursor-type 'bar
cursor-in-non-selected-windows nil)
(blink-cursor-mode 0)
;; Filling text
(setq-default fill-column 80)
(global-display-fill-column-indicator-mode +1)
(bind-key "C-x f" #'find-file) ; I don't set `fill-column', ever
(setq-default comment-auto-fill-only-comments t)
;; Enable `auto-fill-mode' everywhere
(add-hook 'text-mode-hook #'auto-fill-mode)
(add-hook 'prog-mode-hook #'auto-fill-mode)
;; Also enable `visual-line-mode' everywhere
(global-visual-line-mode +1)
;; "Fix" `visual-line-mode' in `org-mode'
(defun hook--visual-line-fix-org-keys ()
(when (derived-mode-p 'org-mode)
(local-set-key (kbd "C-a") #'org-beginning-of-line)
(local-set-key (kbd "C-e") #'org-end-of-line)
(local-set-key (kbd "C-k") #'org-kill-line)))
(add-hook 'visual-line-mode-hook #'hook--visual-line-fix-org-keys)
2021-03-01 20:44:57 +00:00
(dolist (margin '(right-margin left-margin))
(dolist (button '(mouse-1 mouse-2 mouse-3))
(global-set-key (vector margin button)
(global-key-binding (vector button)))))
(mouse-wheel-mode +1)
(when (bound-and-true-p mouse-wheel-mode)
(dolist (margin '(right-margin left-margin))
(dolist (event '(mouse-wheel-down-event
mouse-wheel-up-event
wheel-down
wheel-up
mouse-4
mouse-5))
(global-set-key (vector margin event) #'mwheel-scroll))))
2021-03-01 05:58:57 +00:00
(use-package visual-fill-column
2021-03-01 18:13:28 +00:00
:init (setq-default visual-fill-column-center-text t)
2021-03-01 20:44:57 +00:00
(add-hook 'visual-fill-column-mode-hook #'visual-line-mode)
2021-03-01 18:13:28 +00:00
:config
(advice-add 'text-scale-adjust :after #'visual-fill-column-adjust))
2021-03-01 05:58:57 +00:00
(when (fboundp 'global-so-long-mode)
(global-so-long-mode +1))
;; Whitespace
(setq-default whitespace-style '(empty ; remove blank lines at buffer edges
indentation ; clean up indentation
;; mixed tabs & spaces
space-before-tab
space-after-tab))
(add-hook 'before-save-hook #'whitespace-cleanup)
(setq-default indent-tabs-mode t
tab-width 8)
(use-package smart-tabs-mode
2021-03-01 18:13:28 +00:00
:config
2021-03-01 05:58:57 +00:00
(smart-tabs-insinuate 'c 'c++ 'java 'javascript 'cperl 'python 'ruby 'nxml))
;; Window layouts
(setq-default
split-width-threshold 100 ; minimum width for window splits
split-height-threshold 50 ; minimum height for window splits
display-buffer-alist ; how to display buffers
'((".*" . (display-buffer-reuse-window display-buffer-same-window)))
display-buffer-reuse-frames t ; allow reuse of frames
even-window-sizes nil ; avoid resizing windows to even them
help-window-select t ; select *Help* window when opened
)
(defun vsplit-other-window ()
"Split the window vertically and switch to the new window."
(interactive)
(split-window-vertically)
(other-window 1 nil))
(defun hsplit-other-window ()
"Split the window horizontally and switch to the new window."
(interactive)
(split-window-horizontally)
(other-window 1 nil))
(bind-key "C-x 2" #'vsplit-other-window)
(bind-key "C-x 3" #'hsplit-other-window)
;; Theming
(use-package form-feed
:demand
2021-03-01 18:13:28 +00:00
:config (global-form-feed-mode +1))
2021-03-01 05:58:57 +00:00
(use-package modus-themes
2021-03-01 18:13:28 +00:00
:straight (:host gitlab :repo "protesilaos/modus-themes")
:demand
:init
(setq-default modus-themes-slanted-constructs t
modus-themes-bold-constructs t
modus-themes-region 'bg-only
modus-themes-org-blocks 'grayscale
modus-themes-headings '((1 . section)
(t . no-color))
modus-themes-scale-headings nil
modus-themes-mode-line nil)
:custom-face
(modus-theme-heading-1
((t (:inherit (modus-theme-heading-1 fixed-pitch bold)))))
(modus-theme-heading-2
((t (:inherit (modus-theme-heading-2 fixed-pitch bold)))))
(modus-theme-heading-3
((t (:inherit (modus-theme-heading-3 fixed-pitch bold)))))
(modus-theme-heading-4
((t (:inherit (modus-theme-heading-4 fixed-pitch bold)))))
(modus-theme-heading-5
((t (:inherit (modus-theme-heading-5 fixed-pitch bold)))))
(modus-theme-heading-6
((t (:inherit (modus-theme-heading-6 fixed-pitch bold)))))
(modus-theme-heading-7
((t (:inherit (modus-theme-heading-7 fixed-pitch bold)))))
(modus-theme-heading-8
((t (:inherit (modus-theme-heading-8 fixed-pitch bold))))))
2021-03-01 05:58:57 +00:00
;; Change themes based on time of day
(defun acdw/run-with-sun (sunrise-command sunset-command)
"Run commands at sunrise and sunset."
(let* ((times-regex (rx (* nonl)
(: (any ?s ?S) "unrise") " "
(group (repeat 1 2 digit) ":"
(repeat 1 2 digit)
(: (any ?a ?A ?p ?P) (any ?m ?M)))
(* nonl)
(: (any ?s ?S) "unset") " "
(group (repeat 1 2 digit) ":"
(repeat 1 2 digit)
(: (any ?a ?A ?p ?P) (any ?m ?M)))
(* nonl)))
(ss (sunrise-sunset))
(_m (string-match times-regex ss))
(sunrise-time (match-string 1 ss))
(sunset-time (match-string 2 ss)))
(run-at-time sunrise-time (* 60 60 24) sunrise-command)
(run-at-time sunset-time (* 60 60 24) sunset-command)
(run-at-time "0:00" (* 60 60 24) sunset-command)))
(acdw/run-with-sun #'modus-themes-load-operandi
#'modus-themes-load-vivendi)
(use-package minions
2021-03-01 18:13:28 +00:00
:config (minions-mode +1))
2021-03-01 05:58:57 +00:00
(use-package which-key
2021-03-01 18:13:28 +00:00
:config (which-key-mode +1))
2021-03-01 05:58:57 +00:00
(delete-selection-mode +1)
(setq-default
save-interprogram-paste-before-kill t ; save existing text before replacing
yank-pop-change-selection t ; update X selection when rotating ring
x-select-enable-clipboard t ; Enable X clipboards
x-select-enable-primary t
mouse-drag-copy-region t ; Copy a region when mouse-selected
kill-do-not-save-duplicates t ; Don't append the same thing twice
)
(use-package smartscan
2021-03-01 18:13:28 +00:00
:config (global-smartscan-mode +1))
2021-03-01 05:58:57 +00:00
(when (fboundp 'global-goto-address-mode)
(global-goto-address-mode +1))
(use-package flyspell
2021-03-01 18:13:28 +00:00
:init
2021-03-01 05:58:57 +00:00
(setenv "LANG" "en_US")
(setq-default ispell-program-name "hunspell"
ispell-dictionary "en_US"
ispell-personal-dictionary "~/.hunspell_personal")
:hook
(text-mode . flyspell-mode)
(prog-mode . flyspell-prog-mode)
:config
(ispell-set-spellchecker-params)
(unless (file-exists-p ispell-personal-dictionary)
(write-region "" nil ispell-personal-dictionary nil 0)))
(use-package flyspell-correct
:after flyspell
:bind (:map flyspell-mode-map
("C-;" . flyspell-correct-wrapper)))
2021-03-01 05:58:57 +00:00
(setq-default show-paren-delay 0
show-paren-style 'mixed
show-paren-when-point-inside-paren t
show-paren-when-point-in-periphery t)
(show-paren-mode +1)
(add-hook 'prog-mode-hook #'electric-pair-local-mode)
(setq-default prettify-symbols-unprettify-at-point 'right-edge)
(add-hook 'prog-mode-hook #'prettify-symbols-mode)
(add-hook 'after-save-hook
#'executable-make-buffer-file-executable-if-script-p)
(setq-default compilation-ask-about-save nil ; just save the buffer
compilation-always-kill t ; kill the processes without asking
compilation-scroll-output 'first-error)
(use-package reformatter
2021-03-01 18:13:28 +00:00
:demand)
2021-03-01 05:58:57 +00:00
2021-03-04 15:09:04 +00:00
(setq-default smie-indent-basic 8)
2021-03-01 05:58:57 +00:00
;; Shell scripts
(setq-default sh-basic-offset 8
2021-03-04 15:09:04 +00:00
;; try to indent like shfmt
sh-indent-after-case 0
sh-indent-for-case-alt '+
sh-indent-for-case-label 0)
2021-03-01 05:58:57 +00:00
(use-package flymake-shellcheck
2021-03-01 18:13:28 +00:00
:when (executable-find "shellcheck")
2021-03-04 23:58:44 +00:00
:hook (sh-mode . flymake-shellcheck-load))
2021-03-01 05:58:57 +00:00
(when (executable-find "shfmt")
(reformatter-define sh-format
2021-03-01 18:13:28 +00:00
:program "shfmt"
:lighter "Shfmt")
2021-03-01 05:58:57 +00:00
(add-hook 'sh-mode-hook #'sh-format-on-save-mode))
(bind-key "M-/" #'hippie-expand)
;; Tabs
(setq-default
tab-bar-show 1 ; show the tab bar when more than one
tab-bar-new-tab-choice "*scratch*" ; what to show on a new tab
tab-bar-tab-name-function ; how to name a new tab
#'tab-bar-tab-name-current-with-count
tab-bar-history-limit 25 ; how many tabs to save in history
)
(tab-bar-history-mode +1)
;; Smart hungry delete
(use-package smart-hungry-delete
2021-03-01 18:13:28 +00:00
:defer nil
:bind (("<backspace>" . smart-hungry-delete-backward-char)
("C-d" . smart-hungry-delete-forward-char))
:config (smart-hungry-delete-add-default-hooks))
2021-03-01 05:58:57 +00:00
;; Enable all commands
(setq-default disabled-command-function nil)
;; Magit
(use-package magit
2021-03-01 20:45:31 +00:00
:bind ("C-x g" . magit-status)
:init (when (eq acdw/system :work)
(setenv "GIT_ASKPASS" "git-gui--askpass"))
(defun magit-display-buffer-same-window (buffer)
"Show `magit' in the same buffer, like god intended."
(display-buffer buffer '(display-buffer-same-window)))
(setq magit-display-buffer-function 'magit-display-buffer-same-window
magit-popup-display-buffer-action '((display-buffer-same-window))))
2021-03-01 20:45:31 +00:00
(use-package forge
:after magit)
(use-package gitattributes-mode
:mode "\\.gitattributes\\'")
(use-package gitconfig-mode
:mode "\\.gitconfig\\'")
(use-package gitignore-mode
:mode "\\.gitignore\\'")
2021-03-01 05:58:57 +00:00
;; crux
(use-package crux
2021-03-01 18:13:28 +00:00
:straight (:host github :repo "bbatsov/crux")
:bind
("M-o" . crux-other-window-or-switch-buffer)
:config
(crux-with-region-or-line kill-ring-save)
(crux-with-region-or-line kill-region)
(crux-with-region-or-line comment-or-uncomment-region))
2021-03-01 05:58:57 +00:00
;; Completion and... stuff
(setq-default
completion-ignore-case t
read-buffer-completion-ignore-case t
2021-03-01 20:46:08 +00:00
read-file-name-completion-ignore-case t
minibuffer-eldef-shorten-default t)
(minibuffer-electric-default-mode +1)
2021-03-01 05:58:57 +00:00
(use-package icomplete-vertical
2021-03-01 18:13:28 +00:00
:demand
2021-03-01 05:58:57 +00:00
:init
(setq-default
icomplete-delay-completions-threshold 0
icomplete-max-delay-chars 0
icomplete-compute-delay 0
icomplete-show-matches-on-no-input t
icomplete-hide-common-prefix nil
icomplete-with-completion-tables t
icomplete-in-buffer t)
:bind (:map icomplete-minibuffer-map
("<down>" . icomplete-forward-completions)
("C-n" . icomplete-forward-completions)
("<up>" . icomplete-backward-completions)
("C-p" . icomplete-backward-completions)
("C-v" . icomplete-vertical-toggle))
:config
(fido-mode -1)
(icomplete-mode +1)
(icomplete-vertical-mode +1))
(use-package orderless
2021-03-01 18:13:28 +00:00
:after icomplete
:init (setq-default completion-styles '(orderless)))
2021-03-01 05:58:57 +00:00
(use-package marginalia
2021-03-01 18:13:28 +00:00
:after icomplete
:init (setq-default marginalia-annotators
'(marginalia-annotators-heavy
marginalia-annotators-light))
:config (marginalia-mode +1))
2021-02-26 17:31:50 +00:00
2021-03-01 05:58:57 +00:00
(use-package consult
2021-03-01 18:13:28 +00:00
:after icomplete
:bind (;; C-c bindings (mode-specific-map)
("C-c h" . consult-history)
("C-c m" . consult-mode-command)
("C-c b" . consult-bookmark)
("C-c k" . consult-kmacro)
;; C-x bindings (ctl-x-map)
2021-03-01 20:46:28 +00:00
("C-x M-:" . consult-complex-command)
("C-x b" . consult-buffer)
("C-x 4 b" . consult-buffer-other-window)
("C-x 5 b" . consult-buffer-other-frame)
2021-03-01 18:13:28 +00:00
;; Custom M-# bindings for fast register access
("M-#" . consult-register-load)
2021-03-01 20:46:28 +00:00
("M-'" . consult-register-store)
2021-03-01 18:13:28 +00:00
("C-M-#" . consult-register)
;; Other custom bindings
2021-03-01 20:46:28 +00:00
("M-y" . consult-yank-pop)
("<help> a" . consult-apropos)
2021-03-01 18:13:28 +00:00
;; M-g bindings (goto-map)
("M-g e" . consult-compile-error)
2021-03-01 20:46:28 +00:00
("M-g g" . consult-goto-line)
("M-g M-g" . consult-goto-line)
2021-03-01 18:13:28 +00:00
("M-g o" . consult-outline)
("M-g m" . consult-mark)
("M-g k" . consult-global-mark)
("M-g i" . consult-imenu)
("M-g I" . consult-project-imenu)
;; M-s bindings (search-map)
("M-s f" . consult-find)
("M-s L" . consult-locate)
("M-s g" . consult-grep)
("M-s G" . consult-git-grep)
("M-s r" . consult-ripgrep)
("M-s l" . consult-line)
("M-s m" . consult-multi-occur)
("M-s k" . consult-keep-lines)
("M-s u" . consult-focus-lines)
;; Isearch integration
("M-s e" . consult-isearch)
:map isearch-mode-map
2021-03-01 20:46:28 +00:00
("M-e" . consult-isearch)
("M-s e" . consult-isearch)
("M-s l" . consult-line))
2021-03-01 18:13:28 +00:00
:init
(setq register-preview-delay 0
register-preview-function #'consult-register-format)
(advice-add #'register-preview :override #'consult-register-window)
(setq xref-show-xrefs-function #'consult-xref
xref-show-definitions-function #'consult-xref)
:config
;; (setq consult-preview-key 'any)
;; (setq consult-preview-key (kbd "M-p"))
(setq consult-narrow-key "<"))
;; Language: Emacs-Lisp
(setq-default eval-expression-print-length nil ; don't limit print length
eval-expression-print-level nil
)
;; indent like common lisp
(require 'cl-lib)
(setq-default lisp-indent-function #'common-lisp-indent-function)
(put 'cl-flet 'common-lisp-indent-function
(get 'flet 'common-lisp-indent-function))
(put 'cl-labels 'common-lisp-indent-function
(get 'labels 'common-lisp-indent-function))
(put 'if 'common-lisp-indent-function 2)
(put 'dotimes-protect 'common-lisp-indent-function
(get 'when 'common-lisp-indent-function))
2021-03-02 04:53:56 +00:00
;; eldoc mode
(use-package eldoc
:straight nil
:init (setq-default eldoc-echo-area-display-truncation-message nil
eldoc-idle-delay 0))
2021-03-01 20:46:58 +00:00
;; Dired
(use-package dired
:straight nil
:init
(setq-default dired-recursive-copies 'always
dired-recursive-deletes 'always
delete-by-moving-to-trash t
dired-listing-switches "-AFgho --group-directories-first"
2021-03-02 04:54:03 +00:00
dired-auto-revert-buffer t
2021-03-01 20:46:58 +00:00
dired-dwim-target t)
:bind ("C-x C-j" . dired-jump))
(defun hook--dired-mode ()
(hl-line-mode +1)
(dired-hide-details-mode +1))
(add-hook 'dired-mode-hook #'hook--dired-mode)
(use-package dired-subtree
:bind (:map dired-mode-map
("i" . dired-subtree-toggle)))
(use-package dired-collapse
:hook dired-mode)
(use-package 0x0
:straight (:repo "https://git.sr.ht/~zge/nullpointer-emacs")
:init (setq 0x0-default-service 'ttm)
:commands (0x0-upload
0x0-upload-file
0x0-upload-string
0x0-upload-kill-ring
0x0-popup))
(use-package elpher
:straight (:repo "git://thelambdalab.xyz/elpher.git")
:commands (elpher elpher-bookmarks)
:init (setq elpher-ipv4-always t
elpher-certificate-directory
(expand-file-name "elpher-certificates/"
acdw/var-dir))
(add-hook 'elpher-mode-hook #'acdw/reading-mode)
:custom-face
(elpher-gemini-heading1
((t (:inherit (modus-theme-heading-1)
:height 1.0))))
(elpher-gemini-heading2
((t (:inherit (modus-theme-heading-2)
:height 1.0))))
(elpher-gemini-heading3
((t (:inherit (modus-theme-heading-3)
:height 1.0))))
:bind (:map elpher-mode-map
("n" . elpher-next-link)
("p" . elpher-prev-link)
("o" . elpher-follow-current-link)
("G" . elpher-go-current)))
(use-package gemini-write
:straight (:repo
"https://alexschroeder.ch/cgit/gemini-write"
:fork (:repo "https://tildegit.org/acdw/gemini-write"
:branch "main"))
:after elpher)
(use-package gemini-mode
:straight (:repo "https://git.carcosa.net/jmcbray/gemini.el.git")
:mode "\\.\\(gemini\\|gmi\\)\\'"
:custom-face
(gemini-heading-face-1
((t (:inherit (elpher-gemini-heading1)))))
(gemini-heading-face2
((t (:inherit (elpher-gemini-heading2)))))
(gemini-heading-face3
((t (:inherit (elpher-gemini-heading3))))))
(use-package nov
2021-03-01 22:58:18 +00:00
:init (setq nov-text-width fill-column)
2021-03-01 20:46:58 +00:00
(add-hook 'nov-mode-hook #'acdw/reading-mode)
:mode ("\\.epub\\'" . nov-mode))
(use-package undo-fu
:bind (("C-/" . undo-fu-only-undo)
("C-?" . undo-fu-only-redo)))
(use-package undo-fu-session
:init (setq undo-fu-session-directory (expand-file-name "undo/"
acdw/var-dir)
undo-fu-session-incompatible-files
'("/COMMIT_EDITMSG\\'" "/git-rebase-todo\\'"))
:config (global-undo-fu-session-mode))
(setq-default set-mark-repeat-command-pop t) ; repeat mark pops w/o prefix
(use-package expand-region
:bind ("C-=" . er/expand-region))
(use-package goggles
:hook ((text-mode prog-mode) . goggles-mode))
2021-03-02 04:54:16 +00:00
(use-package isearch
:straight nil)
2021-03-01 20:46:58 +00:00
(use-package anzu
:init (setq search-default-mode t)
:bind (([remap query-replace] . anzu-query-replace-regexp)
([remap query-replace-regexp] . anzu-query-replace)
:map isearch-mode-map
([remap isearch-query-replace] . anzu-isearch-query-replace)
([remap isearch-query-replace-regexp] .
anzu-isearch-query-replace-regexp)))
(use-package iscroll
2021-03-01 22:58:18 +00:00
:hook (text-mode . iscroll-mode))
2021-03-01 20:46:58 +00:00
2021-03-02 04:54:16 +00:00
(use-package ibuffer
:straight nil
2021-03-05 00:36:14 +00:00
:bind ([remap list-buffers] . #'ibuffer)
;; from http://martinowen.net/blog/2010/02/03/tips-for-emacs-ibuffer.html
:init
(setq ibuffer-saved-filter-groups ; this could still be improved
'(("home"
("emacs-config" (or (filename . ".emacs.d")
(filename . "etc/emacs")))
("Org" (or (mode . org-mode)
(filename . "OrgMode")))
("Dired" (mode . dired-mode))
("Magit" (name . "magit"))
("Help" (or (name . "\*Help\*")
(name . "\*Apropos\*")
(name . "\*info\*")))))
ibuffer-expert t ; don't ask if i wanna kill unmodifieds
ibuffer-show-empty-filter-groups nil
)
(defun hook--ibuffer-setup ()
(ibuffer-auto-mode +1)
(ibuffer-switch-to-saved-filter-groups "home"))
(add-hook 'ibuffer-mode-hook #'hook--ibuffer-setup))
2021-03-02 04:54:16 +00:00
2021-03-01 20:46:58 +00:00
(setq-default
browse-url-browser-function 'browse-url-firefox
browse-url-new-window-flag t
browse-url-firefox-new-window-is-tab t
shr-max-width fill-column
shr-width fill-column)
(when (eq acdw/system :work)
(add-to-list 'exec-path "C:/Program Files/Mozilla Firefox"))
2021-03-02 04:54:16 +00:00
(bind-key [remap just-one-space] #'cycle-spacing)
2021-03-04 15:09:29 +00:00
;; Org mode
;; org-return-dwim (unpacakged)
(defun unpackaged/org-element-descendant-of (type element)
"Return non-nil if ELEMENT is a descendant of TYPE.
TYPE should be an element type, like `item' or `paragraph'.
ELEMENT should be a list like that returned by `org-element-context'."
;; MAYBE: Use `org-element-lineage'.
(when-let* ((parent (org-element-property :parent element)))
(or (eq type (car parent))
(unpackaged/org-element-descendant-of type parent))))
(defun unpackaged/org-return-dwim (&optional default)
"A helpful replacement for `org-return'. With prefix, call `org-return'.
On headings, move point to position after entry content. In
lists, insert a new item or end the list, with checkbox if
appropriate. In tables, insert a new row or end the table."
;; Inspired by John Kitchin:
;; http://kitchingroup.cheme.cmu.edu/blog/2017/04/09/A-better-return-in-org-mode/
(interactive "P")
(if default
(org-return)
(cond
;; Act depending on context around point.
;; NOTE: I prefer RET to not follow links, but by uncommenting
;; this block, links will be followed.
;; FURTHER NOTE: Ideally, I would follow links unless point
;; /appeared/ to be at the end of the line (even if it's still
;; inside the link) -- when it would do `org-return'. That
;; would take some /doing/, however.
;; ((eq 'link (car (org-element-context)))
;; ;; Link: Open it.
;; (org-open-at-point-global))
((org-at-heading-p)
;; Heading: Move to position after entry content.
;; NOTE: This is probably the most interesting feature of this function.
(let ((heading-start (org-entry-beginning-position)))
(goto-char (org-entry-end-position))
(cond ((and (org-at-heading-p)
(= heading-start (org-entry-beginning-position)))
;; Entry ends on its heading; add newline after
(end-of-line)
(insert "\n\n"))
(t
;; Entry ends after its heading; back up
(forward-line -1)
(end-of-line)
(when (org-at-heading-p)
;; At the same heading
(forward-line)
(insert "\n")
(forward-line -1))
;; FIXME: looking-back is supposed to be called with
;; more arguments.
(while (not (looking-back (rx
(repeat 3
(seq (optional blank)
"\n")))
nil))
(insert "\n"))
(forward-line -1)))))
((org-at-item-checkbox-p)
;; Checkbox: Insert new item with checkbox.
(org-insert-todo-heading nil))
((org-in-item-p)
;; Plain list. Yes, this gets a little complicated...
(let ((context (org-element-context)))
(if (or (eq 'plain-list (car context)) ; First item in list
(and (eq 'item (car context))
(not (eq (org-element-property :contents-begin context)
(org-element-property :contents-end context))))
;; Element in list item, e.g. a link
(unpackaged/org-element-descendant-of 'item context))
;; Non-empty item: Add new item.
(org-insert-item)
;; Empty item: Close the list.
;; TODO: Do this with org functions rather than operating
;; on the text. Can't seem to find the right function.
(delete-region (line-beginning-position) (line-end-position))
(insert "\n"))))
((when (fboundp 'org-inlinetask-in-task-p)
(org-inlinetask-in-task-p))
;; Inline task: Don't insert a new heading.
(org-return))
((org-at-table-p)
(cond ((save-excursion
(beginning-of-line)
;; See `org-table-next-field'.
(cl-loop with end = (line-end-position)
for cell = (org-element-table-cell-parser)
always (equal (org-element-property :contents-begin cell)
(org-element-property :contents-end cell))
while (re-search-forward "|" end t)))
;; Empty row: end the table.
(delete-region (line-beginning-position) (line-end-position))
(org-return))
(t
;; Non-empty row: call `org-return'.
(org-return))))
(t
;; All other cases: call `org-return'.
(org-return)))))
;; org-fix-blank-lines (unpackaged)
(defun unpackaged/org-fix-blank-lines (&optional prefix)
"Ensure that blank lines exist between headings and between headings and their contents.
With prefix, operate on whole buffer. Ensures that blank lines
exist after each headings's drawers."
(interactive "P")
(org-map-entries (lambda ()
(org-with-wide-buffer
;; `org-map-entries' narrows the buffer, which prevents us
;; from seeing newlines before the current heading, so we
;; do this part widened.
(while (not (looking-back "\n\n" nil))
;; Insert blank lines before heading.
(insert "\n")))
(let ((end (org-entry-end-position)))
;; Insert blank lines before entry content
(forward-line)
(while (and (org-at-planning-p)
(< (point) (point-max)))
;; Skip planning lines
(forward-line))
(while (re-search-forward org-drawer-regexp end t)
;; Skip drawers. You might think that `org-at-drawer-p'
;; would suffice, but for some reason it doesn't work
;; correctly when operating on hidden text. This
;; works, taken from `org-agenda-get-some-entry-text'.
(re-search-forward "^[ \t]*:END:.*\n?" end t)
(goto-char (match-end 0)))
(unless (or (= (point) (point-max))
(org-at-heading-p)
(looking-at-p "\n"))
(insert "\n"))))
t (if prefix
nil
'tree)))
(defun hook--org-mode-fix-blank-lines ()
(when (eq major-mode 'org-mode)
(let ((current-prefix-arg 4)) ; Emulate C-u
(call-interactively 'unpackaged/org-fix-blank-lines))))
(add-hook 'before-save-hook #'hook--org-mode-fix-blank-lines)
(use-package org
:straight (:repo "https://code.orgmode.org/bzg/org-mode.git")
:init
(setq-default
org-directory "~/org" ; where to search for org files
;; typesetting
org-hide-emphasis-markers t
org-fontify-whole-heading-line t
org-fontify-done-headline t
org-fontify-quote-and-verse-blocks t
org-src-fontify-natively t
org-ellipsis ""
org-pretty-entities t
org-tags-column (- 0 fill-column (- (length org-ellipsis)))
;; Source blocks
org-src-tab-acts-natively t
org-src-window-setup 'current-window
org-confirm-babel-evaluate nil
;; Behavior
org-adapt-indentation t ; indent text after a header
org-catch-invisible-edits 'smart
org-special-ctrl-a/e t
org-special-ctrl-k t
org-imenu-depth 8 ; catch all headings
;; Exporting
org-export-headline-levels 8 ; export all headings
org-export-with-smart-quotes t
org-export-with-sub-superscripts t
;; Modules
org-modules '(;; default (commented if unused)
;; bbdb
;; bibtex
;; docview
eww
;; gnus
info
;; irc
;; mhe
;; rmail
;; w3m
;; extra stuff for me
;; habit ; track your consistency with habits
;; inlinetask ; tasks independent of outline hierarchy
mouse ; additional mouse support
;; protocol ; intercept calls from emacsclient
;; man
tempo ; templates
)
org-export-backends '(;; defaults
ascii
html
latex
odt
;; added by me
man
md
)
)
:config
(require 'org-tempo)
(require 'ox-md)
:bind (:map org-mode-map
("RET" . unpackaged/org-return-dwim)))
(use-package goto-addr
:straight nil
:config
(goto-address-mode +1))
(use-package web-mode
:mode (("\\.phtml\\'" . web-mode)
("\\.tpl\\.php\\'" . web-mode)
("\\.[agj]sp\\'" . web-mode)
("\\as[cp]x\\'" . web-mode)
("\\.erb\\'" . web-mode)
("\\.mustache\\'" . web-mode)
("\\.djhtml\\'" . web-mode)
("\\.html?\\'" . web-mode)))