about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorCase Duckworth2023-07-16 22:22:28 -0500
committerCase Duckworth2023-07-16 22:22:28 -0500
commit435e3479fb6968c3b8d7f6f426f31a011fff536f (patch)
tree12f324c593ad4cf737e3595803f4011bb7d6977a
parentChanges! (diff)
downloadetc-435e3479fb6968c3b8d7f6f426f31a011fff536f.tar.gz
etc-435e3479fb6968c3b8d7f6f426f31a011fff536f.zip
nyahhhhh ~~~~~~
-rw-r--r--bash/functions.bash216
-rw-r--r--bash/history.bash2
-rw-r--r--chicken/csirc8
-rw-r--r--emacs.el704
-rw-r--r--user-dirs.dirs7
5 files changed, 654 insertions, 283 deletions
diff --git a/bash/functions.bash b/bash/functions.bash index 4241c8d..66724af 100644 --- a/bash/functions.bash +++ b/bash/functions.bash
@@ -1,143 +1,144 @@
1# Functions 1# Functions
2 2
3memq() { # memq ITEM ARRAY 3memq() { # memq ITEM ARRAY
4 ## Test whether an ITEM is a member of ARRAY. 4 ## Test whether an ITEM is a member of ARRAY.
5 ## Pass ARRAY as ${ARRAY[@]}. 5 ## Pass ARRAY as ${ARRAY[@]}.
6 local e needle="$1" 6 local e needle="$1"
7 shift 7 shift
8 for e; do 8 for e; do
9 [[ "$e" == "$needle" ]] && { 9 [[ "$e" == "$needle" ]] && {
10 return 0 10 return 0
11 } 11 }
12 done 12 done
13 return 1 13 return 1
14} 14}
15 15
16rebashrc() { # rebashrc 16rebashrc() { # rebashrc
17 ## Reload ~/.bashrc 17 ## Reload ~/.bashrc
18 printf "Loading ~/.bashrc..." >&2 18 printf "Loading ~/.bashrc..." >&2
19 if source "$HOME/.bashrc"; then 19 if source "$HOME/.bashrc"; then
20 echo "OK." >&2 20 echo "OK." >&2
21 else 21 else
22 echo "ERROR!" >&2 22 echo "ERROR!" >&2
23 fi 23 fi
24} 24}
25 25
26first_which() { # first_which COMMAND... 26first_which() { # first_which COMMAND...
27 ## Return the fully-qualified path of the first COMMAND found in $PATH. 27 ## Return the fully-qualified path of the first COMMAND found in $PATH.
28 while :; do 28 while :; do
29 command -v "$1" && break 29 command -v "$1" && break
30 [ -z "$1" ] && return 1 30 [ -z "$1" ] && return 1
31 shift 31 shift
32 done 32 done
33} 33}
34 34
35please() { # please [COMMAND...] 35please() { # please [COMMAND...]
36 # if run without arguments, run the last command with 'sudo' (aka sudo !!) 36 # if run without arguments, run the last command with 'sudo' (aka sudo !!)
37 # if run WITH arguments, alias as sudo 37 # if run WITH arguments, alias as sudo
38 history -d -1 38 history -d -1
39 if [ -z "$1" ]; then 39 if [ -z "$1" ]; then
40 #set -- $(HISTTIMEFORMAT=$'\t' history 2 | sed 's/^.*\t//;q') 40 #set -- $(HISTTIMEFORMAT=$'\t' history 2 | sed 's/^.*\t//;q')
41 set -- $(fc -lnr | sed 1q) 41 set -- $(fc -lnr | sed 1q)
42 fi 42 fi
43 echo >&2 sudo "$@" 43 echo >&2 sudo "$@"
44 history -s sudo "$@" 44 history -s sudo "$@"
45 "${DEBUG:-false}" || sudo "$@" 45 "${DEBUG:-false}" || sudo "$@"
46} 46}
47 47
48mkcd() { 48mkcd() {
49 if [ $# -lt 1 ]; then 49 if [ $# -lt 1 ]; then
50 command cd 50 command cd
51 return "$?" 51 return "$?"
52 fi 52 fi
53 if [ "x$1" = x- ]; then 53 if [ "x$1" = x- ]; then
54 command cd - 54 command cd -
55 return "$?" 55 return "$?"
56 fi 56 fi
57 if ! [ -d "$1" ]; then 57 if ! [ -d "$1" ]; then
58 read -p "$1 doesn't exist. Create (y/N)? " yn 58 read -p "$1 doesn't exist. Create (y/N)? " yn
59 case "$yn" in 59 case "$yn" in
60 n* | N*) return 1 ;; 60 n* | N*) return 1 ;;
61 y* | Y*) mkdir -p "$1" ;; 61 y* | Y*) mkdir -p "$1" ;;
62 *) return 1 ;; 62 *) return 1 ;;
63 esac 63 esac
64 fi 64 fi
65 command cd "$1" 65 command cd "$1"
66} 66}
67alias cd='mkcd ' 67alias cd='mkcd '
68 68
69# from tomasino 69# from tomasino
70# alias julian='echo "x = $(date +%s); scale=5; x / 86400 + 2440587.5" | bc' 70# alias julian='echo "x = $(date +%s); scale=5; x / 86400 + 2440587.5" | bc'
71julian() { 71julian() {
72 echo "x = $(date ${1:+-d "$*"} +%s); scale=5; x / 86400 + 2440587.5" | bc 72 echo "x = $(date ${1:+-d "$*"} +%s); scale=5; x / 86400 + 2440587.5" | bc
73} 73}
74 74
75# find files for pipelines 75# find files for pipelines
76f() { 76f() {
77 find "${1:-$PWD}" -depth | 77 find "${1:-$PWD}" -depth |
78 while read -r file; do 78 while read -r file; do
79 printf '%q\n' "$file" 79 printf '%q\n' "$file"
80 done 80 done
81} 81}
82 82
83words() { 83words() {
84 grep -E "$1" /usr/share/dict/words 84 grep -E "$1" /usr/share/dict/words |
85 sed -e '/^[A-Z]/d' -e "/'s$/d"
85} 86}
86 87
87if ! command -v dict >/dev/null 2>&1; then 88if ! command -v dict >/dev/null 2>&1; then
88 dict() { 89 dict() {
89 curl "dict://dict.org/d:$1" | less 90 curl "dict://dict.org/d:$1" | less
90 } 91 }
91fi 92fi
92 93
93if command -v thesauracles >/dev/null 2>&1; then 94if command -v thesauracles >/dev/null 2>&1; then
94 thesauraphrase() { 95 thesauraphrase() {
95 for word in "$@"; do 96 for word in "$@"; do
96 thesauracles -q "$word" 97 thesauracles -q "$word"
97 done | tr '\n' ' ' 98 done | tr '\n' ' '
98 echo 99 echo
99 } 100 }
100fi 101fi
101 102
102up() { 103up() {
103 : "${UP_TODIRECTORY:=..}" 104 : "${UP_TODIRECTORY:=..}"
104 : "${UP_SPECIALARGS:=true}" 105 : "${UP_SPECIALARGS:=true}"
105 local ret=0 106 local ret=0
106 # echo "$UP_TODIRECTORY" "$UP_SPECIALARGS" 107 # echo "$UP_TODIRECTORY" "$UP_SPECIALARGS"
107 if "$UP_SPECIALARGS"; then 108 if "$UP_SPECIALARGS"; then
108 case "$1" in 109 case "$1" in
109 '') cd "$UP_TODIRECTORY" ;; 110 '') cd "$UP_TODIRECTORY" ;;
110 up) UP_TODIRECTORY="${UP_TODIRECTORY}/.." up "${@:2}" ;; 111 up) UP_TODIRECTORY="${UP_TODIRECTORY}/.." up "${@:2}" ;;
111 --) UP_SPECIALARGS=false up "${@:2}" ;; 112 --) UP_SPECIALARGS=false up "${@:2}" ;;
112 -*) if (( "$1" == -1 )); then 113 -*) if (( "$1" == -1 )); then
113 up 114 up
114 else 115 else
115 UP_TODIRECTORY="${UP_TODIRECTORY}/.." up $(( "$1" + 1 )) 116 UP_TODIRECTORY="${UP_TODIRECTORY}/.." up $(( "$1" + 1 ))
116 fi 117 fi
117 ;; 118 ;;
118 *) while cd ..; do 119 *) while cd ..; do
119 case "$PWD" in 120 case "$PWD" in
120 /) ret=1; break ;; 121 /) ret=1; break ;;
121 */"$1") break ;; 122 */"$1") break ;;
122 esac 123 esac
123 done 124 done
124 ;; 125 ;;
125 esac 126 esac
126 else 127 else
127 case "$1" in 128 case "$1" in
128 '') cd "$UP_TODIRECTORY" ;; 129 '') cd "$UP_TODIRECTORY" ;;
129 *) while cd ..; do 130 *) while cd ..; do
130 case "$PWD" in 131 case "$PWD" in
131 /) ret=1; break ;; 132 /) ret=1; break ;;
132 */"$1") break ;; 133 */"$1") break ;;
133 esac 134 esac
134 done 135 done
135 ;; 136 ;;
136 esac 137 esac
137 fi 138 fi
138 UP_TODIRECTORY= 139 UP_TODIRECTORY=
139 UP_SPECIALARGS= 140 UP_SPECIALARGS=
140 return "$ret" 141 return "$ret"
141} 142}
142 143
143apk() { # wrapper for apk(1) 144apk() { # wrapper for apk(1)
@@ -160,3 +161,12 @@ mkssh() {
160 ssh-keygen -t ed25519 -f "$HOME/.ssh/$1" 161 ssh-keygen -t ed25519 -f "$HOME/.ssh/$1"
161 cat "$HOME/.ssh/$1.pub" | tee /dev/stdout | wl-copy 162 cat "$HOME/.ssh/$1.pub" | tee /dev/stdout | wl-copy
162} 163}
164
165p() {
166 cmd="$(history |
167 awk '{for(i=4;i<=NF;i++)printf "%s ",$i;print""}' |
168 tail -n2 |
169 head -n1)"
170 echo "$cmd"
171 eval $cmd
172}
diff --git a/bash/history.bash b/bash/history.bash index d2bdceb..4a458fb 100644 --- a/bash/history.bash +++ b/bash/history.bash
@@ -29,7 +29,7 @@ HISTCONTROL=erasedups
29# identical to 'ignorespace'." -- info (bash)Bash Variables 29# identical to 'ignorespace'." -- info (bash)Bash Variables
30HISTIGNORE='&:[ ]*' 30HISTIGNORE='&:[ ]*'
31# Other commands to ignore 31# Other commands to ignore
32HISTIGNORE="$HISTIGNORE:ls:exit:cd" 32HISTIGNORE="$HISTIGNORE:ls:exit:cd:p"
33 33
34# Automatically append to HISTFILE on every command 34# Automatically append to HISTFILE on every command
35PROMPT_COMMAND="history -a; ${PROMPT_COMMAND:-:}" 35PROMPT_COMMAND="history -a; ${PROMPT_COMMAND:-:}"
diff --git a/chicken/csirc b/chicken/csirc index ac2ef22..0d22235 100644 --- a/chicken/csirc +++ b/chicken/csirc
@@ -3,9 +3,15 @@
3(set! ##sys#notices-enabled #f) 3(set! ##sys#notices-enabled #f)
4(import (chicken load)) 4(import (chicken load))
5(load-verbose #f) 5(load-verbose #f)
6(import (utf8)) 6
7;;; Libraries for interactive development
8;; see also https://www.upyum.com/en/post/7.xhtml
9(import (live-define)
10 (srfi 18))
11
7;; chicken-doc 12;; chicken-doc
8(require-library chicken-doc) 13(require-library chicken-doc)
14
9;; set up breadline 15;; set up breadline
10(let () 16(let ()
11 (import (chicken format)) 17 (import (chicken format))
diff --git a/emacs.el b/emacs.el index ad79286..7e83277 100644 --- a/emacs.el +++ b/emacs.el
@@ -8,31 +8,56 @@
8(add-hook 'after-init-hook 8(add-hook 'after-init-hook
9 (lambda () (load (locate-user-emacs-file "private") :noerror))) 9 (lambda () (load (locate-user-emacs-file "private") :noerror)))
10 10
11(require 'package)
11(add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t) 12(add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t)
12(package-initialize) 13(package-initialize)
13 14
14(defun package-ensure (pkg &optional local require) 15(defun package-ensure (pkg &optional local require)
15 "Ensure PACKAGE is installed. 16 "Ensure PKG is installed.
16If LOCAL is t, add ~/src/PKG.el to `load-path' and generate autoloads. 17PKG can be a symbol, a string, or a list. A symbol will be
17If REQUIRE is non-nil, require it as well." 18installed using `package-install' from `package-archives'. A
19string will use `package-vc-install', which see. If given a
20list, it will be interpreted as a full set of arguments to one of
21the above functions, depending on the type of its car.
22
23If LOCAL is t, add ~/src/PKG.el to `load-path' and generate
24autoloads. If LOCAL is a string, Add that directory to
25`load-path'.
26
27If REQUIRE is non-nil, require the package after installing it."
28 (setq pkg (ensure-list pkg))
29
18 (cond 30 (cond
19 ((stringp local) 31 (local
32 (unless (stringp local)
33 (setq local (expand-file-name
34 (format "~/src/%s.el" (car pkg)))))
20 (unless (file-directory-p local) 35 (unless (file-directory-p local)
21 (user-error "Package directory does not exist: %s" local)) 36 (user-error "Package directory does not exist: %s" local))
22 (let ((autoload-file (expand-file-name (format "%s-autoloads.el" pkg) local)) 37 (let ((autoload-file (expand-file-name
38 (format "%s-autoloads.el" (car pkg))
39 local))
23 (backup-inhibited t)) 40 (backup-inhibited t))
24 (add-to-list 'load-path local) 41 (add-to-list 'load-path local)
25 (loaddefs-generate local autoload-file) 42 (loaddefs-generate local autoload-file)
26 (load autoload-file nil t))) 43 (load autoload-file nil t))
27 (local 44 (setq pkg (intern (format "%s" (car pkg)))))
28 (package-ensure pkg (expand-file-name (format "~/src/%s.el" pkg)) require)) 45
29 (:else 46 ((symbolp (car pkg))
30 (unless (package-installed-p pkg) 47 (unless (ignore-errors (apply #'package-install pkg))
31 (unless (ignore-errors (package-install pkg)) 48 (package-refresh-contents)
32 (package-refresh-contents) 49 (apply #'package-install pkg))
33 (package-install pkg))))) 50 (setq pkg (car pkg)))
51
52 ((stringp (car pkg))
53 (let ((pkg-name (intern (file-name-base (car pkg)))))
54 (unless (package-installed-p pkg-name)
55 (apply #'package-vc-install pkg))
56 (setq pkg pkg-name))))
57
34 (when require 58 (when require
35 (require pkg)) 59 (require pkg))
60
36 pkg) 61 pkg)
37 62
38(defmacro setf/assoc (alist key val &optional keep) 63(defmacro setf/assoc (alist key val &optional keep)
@@ -45,6 +70,11 @@ KEEP is also non-nil."
45 70
46(defmacro comment (&rest _) (declare (indent defun)) nil) 71(defmacro comment (&rest _) (declare (indent defun)) nil)
47 72
73(defun add-local-mode-hook (mode-hook hook func)
74 "Add FUNC to HOOK locally in buffers with MODE-HOOK."
75 (add-hook mode-hook
76 (lambda () (add-hook hook func nil t))))
77
48(package-ensure 'crux) 78(package-ensure 'crux)
49(crux-reopen-as-root-mode) 79(crux-reopen-as-root-mode)
50 80
@@ -54,6 +84,12 @@ KEEP is also non-nil."
54 84
55(keymap-global-set "C-c i" #'crux-find-user-init-file) 85(keymap-global-set "C-c i" #'crux-find-user-init-file)
56 86
87(setopt auth-sources '(default
88 "secrets:passwords"
89 "~/.authinfo"))
90
91(setq disabled-command-function nil)
92
57 93
58;;; Theme 94;;; Theme
59 95
@@ -67,6 +103,8 @@ KEEP is also non-nil."
67(scroll-bar-mode -1) 103(scroll-bar-mode -1)
68(tooltip-mode -1) 104(tooltip-mode -1)
69 105
106(setopt scroll-conservatively 101)
107
70(setopt read-answer-short t) 108(setopt read-answer-short t)
71(setopt use-dialog-box nil) 109(setopt use-dialog-box nil)
72(setopt use-file-dialog nil) 110(setopt use-file-dialog nil)
@@ -109,20 +147,21 @@ KEEP is also non-nil."
109 font-lock-bracket-face)) 147 font-lock-bracket-face))
110 (face-spec-set face '((t :foreground unspecified 148 (face-spec-set face '((t :foreground unspecified
111 :background unspecified)))) 149 :background unspecified))))
112 (dolist (face '(font-lock-doc-face
113 font-lock-string-face))
114 (face-spec-set face '((t :foreground unspecified
115 :background unspecified
116 :slant italic))))
117 (when-let ((current (cl-loop for modus in '(modus-vivendi modus-operandi) 150 (when-let ((current (cl-loop for modus in '(modus-vivendi modus-operandi)
118 if (memq modus custom-enabled-themes) 151 if (memq modus custom-enabled-themes)
119 return modus 152 return modus
120 finally return nil))) 153 finally return nil)))
121 (face-spec-set 'font-lock-comment-face 154 (modus-themes-with-colors
122 `((t :foreground ; :inherit doesn't work for some reason?? 155 (dolist (face '(font-lock-doc-face
123 ,(if (eq current 'modus-operandi) 156 font-lock-string-face))
124 "#7c318f" 157 (face-spec-set face `((t :foreground unspecified
125 "#caa6df")))))) 158 :background unspecified
159 :slant italic))))
160 ;; (face-spec-set 'font-lock-comment-face
161 ;; :inherit doesn't work for some reason??
162 ;; `((t :foreground
163 ;; ,fg-alt)))
164 )))
126(advice-add 'load-theme :after #'reset-faces) 165(advice-add 'load-theme :after #'reset-faces)
127 166
128(load-theme 'modus-vivendi :no-confirm :no-enable) 167(load-theme 'modus-vivendi :no-confirm :no-enable)
@@ -274,7 +313,11 @@ mouse-3: Toggle minor modes"
274;;; Completion and minibuffer 313;;; Completion and minibuffer
275 314
276(setopt tab-always-indent 'complete) 315(setopt tab-always-indent 'complete)
277;; (setopt completion-styles '(basic partial-completion substring flex)) 316(setopt completion-styles '(basic partial-completion substring flex))
317
318;; XXX: this is 'too good' when I'm in the process of typing out things.
319;; (when (package-ensure "https://git.sr.ht/~pkal/typo")
320;; (add-to-list 'completion-styles 'typo :append))
278 321
279(setopt completion-ignore-case t) 322(setopt completion-ignore-case t)
280(setopt read-buffer-completion-ignore-case t) 323(setopt read-buffer-completion-ignore-case t)
@@ -289,15 +332,30 @@ mouse-3: Toggle minor modes"
289(setopt completions-format 'one-column) 332(setopt completions-format 'one-column)
290(setopt completions-max-height 20) 333(setopt completions-max-height 20)
291 334
335;; (defun minibuffer-next-completion-or-line (n)
336;; "Move to the next N completion in minibuffer, or Nth next line."
337;; (interactive "p")
338;; (if (and (eq last-command 'minibuffer-next-completion)
339;; (not (minibufferp)))
340;; (forward-line n)
341;; (minibuffer-next-completion n)))
342
343;; (defun minibuffer-previous-completion-or-line (n)
344;; "Move to the previous N completion, or Nth previous line."
345;; (interactive "p")
346;; (setq last-command 'minibuffer-next-completion-or-line)
347;; (minibuffer-next-completion-or-line (- n)))
348
292(progn 349(progn
293 (keymap-set minibuffer-local-map "C-p" 350 (keymap-set minibuffer-local-map "C-p"
294 #'minibuffer-previous-completion) 351 #'minibuffer-previous-completion)
295 (keymap-set minibuffer-local-map "C-n" 352 (keymap-set minibuffer-local-map "C-n"
296 #'minibuffer-next-completion) 353 #'minibuffer-next-completion)
297 (keymap-set completion-in-region-mode-map "C-p" 354 ;; (keymap-set completion-in-region-mode-map "C-p"
298 #'minibuffer-previous-completion) 355 ;; #'minibuffer-previous-completion)
299 (keymap-set completion-in-region-mode-map "C-n" 356 ;; (keymap-set completion-in-region-mode-map "C-n"
300 #'minibuffer-next-completion)) 357 ;; #'minibuffer-next-completion)
358 )
301 359
302(setf/assoc display-buffer-alist 360(setf/assoc display-buffer-alist
303 "\\*Completions\\*" 361 "\\*Completions\\*"
@@ -318,11 +376,6 @@ mouse-3: Toggle minor modes"
318(add-hook 'completion-list-mode-hook #'truncate-lines-local-mode) 376(add-hook 'completion-list-mode-hook #'truncate-lines-local-mode)
319(add-hook 'minibuffer-setup-hook #'truncate-lines-local-mode) 377(add-hook 'minibuffer-setup-hook #'truncate-lines-local-mode)
320 378
321(when (package-ensure 'orderless)
322 (setopt completion-styles '(substring orderless basic))
323 (setopt completion-category-overrides
324 '((file (styles basic partial-completion)))))
325
326(when (package-ensure 'consult nil t) 379(when (package-ensure 'consult nil t)
327 (keymap-global-set "C-x b" #'consult-buffer) 380 (keymap-global-set "C-x b" #'consult-buffer)
328 (keymap-global-set "C-x 4 b" #'consult-buffer-other-window) 381 (keymap-global-set "C-x 4 b" #'consult-buffer-other-window)
@@ -439,6 +492,8 @@ mouse-3: Toggle minor modes"
439(keymap-global-set "M-/" #'hippie-expand) 492(keymap-global-set "M-/" #'hippie-expand)
440(keymap-global-set "C-x C-b" #'ibuffer) 493(keymap-global-set "C-x C-b" #'ibuffer)
441 494
495(add-hook 'ibuffer-mode-hook #'hl-line-mode)
496
442(defun call-with-region-or-buffer (fn &rest _r) 497(defun call-with-region-or-buffer (fn &rest _r)
443 "Call function FN with current region or buffer. 498 "Call function FN with current region or buffer.
444Good to use for :around advice." 499Good to use for :around advice."
@@ -481,7 +536,7 @@ Good to use for :around advice."
481(defun org-fk-region (start end) 536(defun org-fk-region (start end)
482 "Get the Flesch-Kincaid score of an `org-mode' region." 537 "Get the Flesch-Kincaid score of an `org-mode' region."
483 (interactive "r") 538 (interactive "r")
484 (let ((buf (get-buffer-create "*fk*" t))) 539 (let ((buf (get-buffer-create " *fk*" t)))
485 (shell-command-on-region start end 540 (shell-command-on-region start end
486 "pandoc -t plain -f org | ~/src/fk/fk.perl" 541 "pandoc -t plain -f org | ~/src/fk/fk.perl"
487 buf) 542 buf)
@@ -506,6 +561,8 @@ Good to use for :around advice."
506 (unless (ignore-errors (dictionary-lookup-definition)) 561 (unless (ignore-errors (dictionary-lookup-definition))
507 (call-interactively #'dictionary-search)))) 562 (call-interactively #'dictionary-search))))
508 563
564(package-ensure 'markdown-mode)
565
509;;; Programming 566;;; Programming
510 567
511(setopt electric-pair-skip-whitespace 'chomp) 568(setopt electric-pair-skip-whitespace 'chomp)
@@ -533,6 +590,7 @@ Good to use for :around advice."
533(setopt tab-width 8) 590(setopt tab-width 8)
534 591
535(defvar space-indent-modes '(emacs-lisp-mode 592(defvar space-indent-modes '(emacs-lisp-mode
593 lisp-interaction-mode
536 lisp-mode 594 lisp-mode
537 scheme-mode 595 scheme-mode
538 python-mode 596 python-mode
@@ -552,7 +610,8 @@ Good to use for :around advice."
552 610
553(when (package-ensure 'geiser) 611(when (package-ensure 'geiser)
554 (when (executable-find "csi") 612 (when (executable-find "csi")
555 (package-ensure 'geiser-chicken)) 613 (when (package-ensure 'geiser-chicken)
614 (setf/assoc auto-mode-alist "\\.egg\\'" 'scheme-mode))))
556 (setopt scheme-program-name (or (executable-find "csi") 615 (setopt scheme-program-name (or (executable-find "csi")
557 "scheme")) 616 "scheme"))
558 (add-hook 'scheme-mode-hook #'geiser-mode)) 617 (add-hook 'scheme-mode-hook #'geiser-mode))
@@ -566,6 +625,19 @@ Good to use for :around advice."
566 _ \n 625 _ \n
567 "|#" \n \n)) 626 "|#" \n \n))
568 627
628;; Emacs lisp
629
630(keymap-set emacs-lisp-mode-map "C-c C-c" #'eval-defun)
631(keymap-set emacs-lisp-mode-map "C-c C-b" #'eval-buffer)
632(keymap-set emacs-lisp-mode-map "C-c C-z" #'ielm) ; TODO: better-ize
633(keymap-set lisp-interaction-mode-map "C-c C-c" #'eval-defun)
634(keymap-set lisp-interaction-mode-map "C-c C-b" #'eval-buffer)
635(keymap-set lisp-interaction-mode-map "C-c C-z" #'ielm) ; TODO: better-ize
636
637
638(define-advice eval-buffer (:after (&rest _) message)
639 (message "Buffer %s evaluated." (current-buffer)))
640
569 641
570;;; Files 642;;; Files
571 643
@@ -640,18 +712,33 @@ Good to use for :around advice."
640 712
641;;; ... 713;;; ...
642 714
715(defun c-w-dwim (num)
716 "Delete NUM words backward, or the region if it's active."
717 (interactive "p")
718 (if (region-active-p)
719 (call-interactively #'kill-region)
720 (call-interactively #'backward-kill-word)))
721(keymap-global-set "C-w" #'c-w-dwim)
722
723(setf/assoc display-buffer-alist
724 "\\`\\*Warnings\\*"
725 '((display-buffer-no-window)))
726
727(winner-mode)
728
643(setopt set-mark-command-repeat-pop t) 729(setopt set-mark-command-repeat-pop t)
644 730
645(when (package-ensure 'embark nil t) 731(when (package-ensure 'embark nil t)
646 (when (package-installed-p 'consult) 732 (when (and (package-installed-p 'consult)
647 (package-ensure 'embark-consult nil t)) 733 (package-ensure 'embark-consult nil t))
734 (add-hook 'embark-collect-mode-hook #'consult-preview-at-point-mode))
648 (keymap-global-set "C-." #'embark-act) 735 (keymap-global-set "C-." #'embark-act)
649 (keymap-global-set "M-." #'embark-dwim) 736 (keymap-global-set "M-." #'embark-dwim)
650 (keymap-global-set "C-h B" #'embark-bindings) 737 (keymap-global-set "C-h B" #'embark-bindings)
738 (setopt prefix-help-command #'embark-prefix-help-command)
651 (setf/assoc display-buffer-alist 739 (setf/assoc display-buffer-alist
652 "\\`\\*Embark Collect \\(Live\\|Completions\\)\\*" 740 "\\`\\*Embark Collect \\(Live\\|Completions\\)\\*"
653 '(nil (window-parameters (mode-line-format . none)))) 741 '(nil (window-parameters (mode-line-format . none)))))
654 (add-hook 'embark-collect-mode-hook #'consult-preview-at-point-mode))
655 742
656(setopt eldoc-documentation-strategy #'eldoc-documentation-compose-eagerly) 743(setopt eldoc-documentation-strategy #'eldoc-documentation-compose-eagerly)
657(setopt eldoc-idle-delay 0.01) 744(setopt eldoc-idle-delay 0.01)
@@ -692,23 +779,6 @@ Good to use for :around advice."
692 (delete-trailing-whitespace (line-end-position) 779 (delete-trailing-whitespace (line-end-position)
693 (point-max))))) 780 (point-max)))))
694 781
695(defcustom browse-url-safe-browser-functions nil
696 "\"Safe\" browser functions."
697 :type '(repeat-function))
698
699(defun browse-url-browser-function-safe-p (fn)
700 "Return t if FN is a \"safe\" browser function."
701 (memq fn (append browse-url-safe-browser-functions
702 (mapcar (lambda (i)
703 (plist-get (cdr i) :value))
704 (seq-filter (lambda (i)
705 (eq (car i) 'function-item))
706 (cdr (get 'browse-url-browser-function
707 'custom-type)))))))
708
709(put 'browse-url-browser-function 'safe-local-variable
710 'browse-url-browser-function-safe-p)
711
712(defun list-of-strings-p (x) 782(defun list-of-strings-p (x)
713 "Is X a list of strings?" 783 "Is X a list of strings?"
714 (and x 784 (and x
@@ -732,29 +802,44 @@ Good to use for :around advice."
732 (repunctuate-sentences :no-query start end) 802 (repunctuate-sentences :no-query start end)
733 (fill-region start end))) 803 (fill-region start end)))
734 804
735(defun fill-or-unfill-region (start end) 805(defun unfill-region (start end &optional unfill-func)
806 "Unfill region from START to END."
807 (let ((fill-column most-positive-fixnum)
808 (fill-paragraph-function nil))
809 (funcall (or unfill-func #'fill-region) start end)))
810
811(defun fill-or-unfill-region (start end &optional interactive)
736 "Fill or unfill from START to END." 812 "Fill or unfill from START to END."
737 (let ((filled-p (cl-every (lambda (ln) (<= (length ln) fill-column)) 813 (interactive "*r\np")
738 (string-split (buffer-substring start end) 814 (if (and interactive
739 "[\n\r]+")))) 815 (eq last-command 'fill-or-unfill-region))
740 (if filled-p 816 ;; If called interactively more than once, toggle filling mode.
741 (let ((fill-column most-positive-fixnum) 817 (if (with-current-buffer "*Messages*"
742 (fill-paragraph-function nil)) 818 (goto-char (point-max))
743 (message "Unfilling region") 819 (goto-char (beginning-of-line))
744 (fill-double-space-sentences-region start end)) 820 (looking-at "Unfilling"))
745 (message "Filling region") 821 (fill-double-space-sentences-region start end)
746 (fill-double-space-sentences-region start end)))) 822 (unfill-region start end #'fill-double-space-sentences-region))
823 ;; Otherwise, detect filled status based on the length of lines in the
824 ;; region. If just one of them is longer than `fill-column', consider the
825 ;; region unfilled.
826 (let ((filled-p (cl-some (lambda (ln) (<= 1 (length ln) fill-column))
827 (string-split (buffer-substring start end)
828 "[\n\r]+"))))
829 (if filled-p
830 (progn
831 (message "Unfilling region")
832 (unfill-region start end #'fill-double-space-sentences-region))
833 (progn
834 (message "Filling region")
835 (fill-double-space-sentences-region start end))))))
747 836
748(defun fill-or-unfill-dwim () 837(defun fill-or-unfill-dwim ()
749 (interactive) 838 (interactive)
750 (save-mark-and-excursion 839 (save-mark-and-excursion
751 (if (region-active-p) 840 (unless (region-active-p)
752 (fill-or-unfill-region (region-beginning) 841 (mark-paragraph))
753 (region-end)) 842 (call-interactively #'fill-or-unfill-region)))
754 (fill-or-unfill-region (progn (backward-paragraph)
755 (point))
756 (progn (forward-paragraph)
757 (point))))))
758 843
759(keymap-global-set "M-q" #'fill-or-unfill-dwim) 844(keymap-global-set "M-q" #'fill-or-unfill-dwim)
760 845
@@ -788,6 +873,7 @@ In these cases, switch to the last-used buffer."
788 (switch-to-buffer (other-buffer) nil t) 873 (switch-to-buffer (other-buffer) nil t)
789 (other-window 1))) 874 (other-window 1)))
790(keymap-global-set "M-o" #'other-window-dwim) 875(keymap-global-set "M-o" #'other-window-dwim)
876(keymap-global-set "C-x o" #'other-window-dwim)
791 877
792(defun delete-window-dwim () 878(defun delete-window-dwim ()
793 "Delete the current window or bury its buffer. 879 "Delete the current window or bury its buffer.
@@ -1000,6 +1086,31 @@ ORG-EXPORT-ARGS are passed to `org-export-to-buffer'."
1000 (org-todo (if (= n-not-done 0) "DONE" "TODO")))) 1086 (org-todo (if (= n-not-done 0) "DONE" "TODO"))))
1001(add-hook 'org-after-todo-statistics-hook #'org-summary-todo) 1087(add-hook 'org-after-todo-statistics-hook #'org-summary-todo)
1002 1088
1089;; Clean up the buffer view
1090(defun org-hide-drawers-except-point ()
1091 "Hide all drawers except for the one point is in."
1092 ;; Most of this bit is taken from `org-fold--hide-drawers'.
1093 (let ((pt (point))
1094 (begin (point-min))
1095 (end (point-max)))
1096 (save-excursion
1097 (goto-char begin)
1098 (while (and (< (point) end)
1099 (re-search-forward org-drawer-regexp end t))
1100 (if (org-fold-folded-p nil 'drawer)
1101 (goto-char (org-fold-next-folding-state-change 'drawer nil end))
1102 (let* ((drawer (org-element-at-point))
1103 (type (org-element-type drawer))
1104 (el-begin (org-element-property :begin drawer))
1105 (el-end (org-element-property :end drawer)))
1106 (when (memq type '(drawer property-drawer))
1107 (org-fold-hide-drawer-toggle
1108 (if (< el-begin pt el-end) 'off 'on)
1109 nil drawer)
1110 (goto-char el-end))))))))
1111(add-local-mode-hook 'org-mode-hook 'before-save-hook
1112 #'org-hide-drawers-except-point)
1113
1003;; Fix braindead behavior 1114;; Fix braindead behavior
1004(with-eval-after-load 'org-mouse 1115(with-eval-after-load 'org-mouse
1005 (defun org--mouse-open-at-point (orig-fun &rest args) 1116 (defun org--mouse-open-at-point (orig-fun &rest args)
@@ -1079,7 +1190,7 @@ the following: `:keys', `:description', `:type', `:target', and
1079 ;; (string-chop-newline (buffer-substring-no-properties 1190 ;; (string-chop-newline (buffer-substring-no-properties
1080 ;; (line-beginning-position) (point-max))))) 1191 ;; (line-beginning-position) (point-max)))))
1081 1192
1082 (let ((shell-command-buffer-name (format "*fk/%s*" (buffer-name)))) 1193 (let ((shell-command-buffer-name (format " *fk/%s*" (buffer-name))))
1083 (shell-command-on-region start end "~/src/fk/fk.perl") 1194 (shell-command-on-region start end "~/src/fk/fk.perl")
1084 (with-current-buffer shell-command-buffer-name 1195 (with-current-buffer shell-command-buffer-name
1085 (buffer-substring-no-properties (point-min) (- (point-max) 1)))) 1196 (buffer-substring-no-properties (point-min) (- (point-max) 1))))
@@ -1153,102 +1264,102 @@ the following: `:keys', `:description', `:type', `:target', and
1153 1264
1154;;; Jabber 1265;;; Jabber
1155 1266
1156(when (package-ensure 'jabber t t) 1267;; (when (package-ensure 'jabber t t)
1157 (setopt jabber-chat-buffer-format "*%n*") 1268;; (setopt jabber-chat-buffer-format "*%n*")
1158 (setopt jabber-browse-buffer-format "*%n*") 1269;; (setopt jabber-browse-buffer-format "*%n*")
1159 (setopt jabber-groupchat-buffer-format "*%n*") 1270;; (setopt jabber-groupchat-buffer-format "*%n*")
1160 (setopt jabber-muc-private-buffer-format "*%n*") 1271;; (setopt jabber-muc-private-buffer-format "*%n*")
1161 1272
1162 (face-spec-set 'jabber-activity-face 1273;; (face-spec-set 'jabber-activity-face
1163 '((t :inherit jabber-chat-prompt-foreign 1274;; '((t :inherit jabber-chat-prompt-foreign
1164 :foreground unspecified 1275;; :foreground unspecified
1165 :weight normal))) 1276;; :weight normal)))
1166 (face-spec-set 'jabber-activity-personal-face 1277;; (face-spec-set 'jabber-activity-personal-face
1167 '((t :inherit jabber-chat-prompt-local 1278;; '((t :inherit jabber-chat-prompt-local
1168 :foreground unspecified 1279;; :foreground unspecified
1169 :weight bold))) 1280;; :weight bold)))
1170 (face-spec-set 'jabber-chat-prompt-local 1281;; (face-spec-set 'jabber-chat-prompt-local
1171 '((t :inherit minibuffer-prompt 1282;; '((t :inherit minibuffer-prompt
1172 :foreground unspecified 1283;; :foreground unspecified
1173 :weight normal 1284;; :weight normal
1174 :slant italic))) 1285;; :slant italic)))
1175 (face-spec-set 'jabber-chat-prompt-foreign 1286;; (face-spec-set 'jabber-chat-prompt-foreign
1176 '((t :inherit warning 1287;; '((t :inherit warning
1177 :foreground unspecified 1288;; :foreground unspecified
1178 :weight normal))) 1289;; :weight normal)))
1179 (face-spec-set 'jabber-chat-prompt-system 1290;; (face-spec-set 'jabber-chat-prompt-system
1180 '((t :inherit font-lock-doc-face 1291;; '((t :inherit font-lock-doc-face
1181 :foreground unspecified))) 1292;; :foreground unspecified)))
1182 (face-spec-set 'jabber-rare-time-face 1293;; (face-spec-set 'jabber-rare-time-face
1183 '((t :inherit font-lock-comment-face 1294;; '((t :inherit font-lock-comment-face
1184 :foreground unspecified 1295;; :foreground unspecified
1185 :underline nil))) 1296;; :underline nil)))
1186 1297
1187 (setopt jabber-auto-reconnect t) 1298;; (setopt jabber-auto-reconnect t)
1188 (setopt jabber-last-read-marker 1299;; (setopt jabber-last-read-marker
1189 "-------------------------------------------------------------------") 1300;; "-------------------------------------------------------------------")
1190 (setopt jabber-muc-decorate-presence-patterns 1301;; (setopt jabber-muc-decorate-presence-patterns
1191 '(("\\( enters the room ([^)]+)\\| has left the chatroom\\)$" . nil) 1302;; '(("\\( enters the room ([^)]+)\\| has left the chatroom\\)$" . nil)
1192 ("Mode #.*" . jabber-muc-presence-dim) 1303;; ("Mode #.*" . jabber-muc-presence-dim)
1193 ("." . jabber-muc-presence-dim))) 1304;; ("." . jabber-muc-presence-dim)))
1194 (setopt jabber-activity-make-strings #'jabber-activity-make-strings-shorten) 1305;; (setopt jabber-activity-make-strings #'jabber-activity-make-strings-shorten)
1195 (setopt jabber-rare-time-format 1306;; (setopt jabber-rare-time-format
1196 (format " - - - - - %%H:%d %%F" 1307;; (format " - - - - - %%H:%d %%F"
1197 (let ((min (string-to-number (format-time-string "%M")))) 1308;; (let ((min (string-to-number (format-time-string "%M"))))
1198 (* 5 (floor min 5))))) 1309;; (* 5 (floor min 5)))))
1199 (setopt jabber-muc-header-line-format '(" " jabber-muc-topic)) 1310;; (setopt jabber-muc-header-line-format '(" " jabber-muc-topic))
1200 1311
1201 (setopt jabber-groupchat-prompt-format "%n. ") 1312;; (setopt jabber-groupchat-prompt-format "%n. ")
1202 (setopt jabber-chat-local-prompt-format "%n. ") 1313;; (setopt jabber-chat-local-prompt-format "%n. ")
1203 (setopt jabber-chat-foreign-prompt-format "%n. ") 1314;; (setopt jabber-chat-foreign-prompt-format "%n. ")
1204 (setopt jabber-muc-private-foreign-prompt-format "%g/%n. ") 1315;; (setopt jabber-muc-private-foreign-prompt-format "%g/%n. ")
1205 1316
1206 (defun jabber-connect-all* (&optional arg) 1317;; (defun jabber-connect-all* (&optional arg)
1207 "Connect to all defined jabber accounts. 1318;; "Connect to all defined jabber accounts.
1208If called with ARG non-nil, or with \\[universal-argument], 1319;; If called with ARG non-nil, or with \\[universal-argument],
1209disconnect first." 1320;; disconnect first."
1210 (interactive "P") 1321;; (interactive "P")
1211 (when arg (jabber-disconnect)) 1322;; (when arg (jabber-disconnect))
1212 (jabber-connect-all)) 1323;; (jabber-connect-all))
1213 1324
1214 (keymap-global-set "C-c C-SPC" #'jabber-activity-switch-to) 1325;; (with-eval-after-load 'jabber
1215 (with-eval-after-load 'jabber 1326;; (keymap-global-set "C-c C-SPC" #'jabber-activity-switch-to)
1216 (require 'jabber-httpupload nil t) 1327;; (require 'jabber-httpupload nil t)
1217 (map-keymap (lambda (key command) 1328;; (map-keymap (lambda (key command)
1218 (define-key jabber-global-keymap (vector (+ key #x60)) command)) 1329;; (define-key jabber-global-keymap (vector (+ key #x60)) command))
1219 jabber-global-keymap) 1330;; jabber-global-keymap)
1220 (keymap-global-set "C-x C-j" #'dired-jump)) 1331;; (keymap-global-set "C-x C-j" #'dired-jump)
1221 (keymap-global-set "C-x C-j" #'dired-jump) 1332;; (keymap-set jabber-global-keymap "c" #'jabber-connect-all*)
1222 (keymap-set jabber-global-keymap "c" #'jabber-connect-all*) 1333;; (keymap-global-set "C-c j" jabber-global-keymap))
1223 (keymap-global-set "C-c j" jabber-global-keymap) 1334
1224 1335;; (remove-hook 'jabber-alert-muc-hooks #'jabber-muc-echo)
1225 (remove-hook 'jabber-alert-muc-hooks #'jabber-muc-echo) 1336;; (remove-hook 'jabber-alert-presence-hooks #'jabber-presence-echo)
1226 (remove-hook 'jabber-alert-presence-hooks #'jabber-presence-echo) 1337;; (add-hook 'jabber-post-connect-hooks #'jabber-enable-carbons)
1227 (add-hook 'jabber-post-connect-hooks #'jabber-enable-carbons) 1338;; (add-hook 'jabber-chat-mode-hook #'olivetti-mode)
1228 (add-hook 'jabber-chat-mode-hook #'olivetti-mode) 1339;; (add-hook 'jabber-chat-mode-hook
1229 (add-hook 'jabber-chat-mode-hook 1340;; (defun jabber-chat-mode-no-position ()
1230 (defun jabber-chat-mode-no-position () 1341;; (setq-local mode-line-position nil)))
1231 (setq-local mode-line-position nil))) 1342;; (add-hook 'jabber-alert-muc-hooks
1232 (add-hook 'jabber-alert-muc-hooks 1343;; (defun jabber@highlight-acdw (&optional _ _ buf _ _)
1233 (defun jabber@highlight-acdw (&optional _ _ buf _ _) 1344;; (when buf
1234 (when buf 1345;; (with-current-buffer buf
1235 (with-current-buffer buf 1346;; (let ((regexp (rx word-boundary
1236 (let ((regexp (rx word-boundary 1347;; "acdw" ; maybe get from the config?
1237 "acdw" ; maybe get from the config? 1348;; word-boundary)))
1238 word-boundary))) 1349;; (hi-lock-unface-buffer regexp)
1239 (hi-lock-unface-buffer regexp) 1350;; (highlight-regexp regexp 'jabber-chat-prompt-local))))))
1240 (highlight-regexp regexp 'jabber-chat-prompt-local)))))) 1351
1241 1352;; (add-hook 'jabber-chat-mode-hook
1242 (add-hook 'jabber-chat-mode-hook 1353;; (defun electric-pair-local-disable ()
1243 (defun electric-pair-local-disable () 1354;; (electric-pair-local-mode -1)))
1244 (electric-pair-local-mode -1))) 1355
1245 1356;; (when (fboundp 'jabber-chat-update-focus)
1246 (when (fboundp 'jabber-chat-update-focus) 1357;; (add-hook 'window-configuration-change-hook #'jabber-chat-update-focus)))
1247 (add-hook 'window-configuration-change-hook #'jabber-chat-update-focus)))
1248 1358
1249 1359
1250;;; Dired 1360;;; Dired
1251 1361
1362(keymap-global-set "C-x C-j" #'dired-jump)
1252(with-eval-after-load 'dired 1363(with-eval-after-load 'dired
1253 (keymap-set dired-mode-map "C-j" #'dired-up-directory)) 1364 (keymap-set dired-mode-map "C-j" #'dired-up-directory))
1254 1365
@@ -1257,6 +1368,23 @@ disconnect first."
1257 1368
1258(setopt browse-url-browser-function #'eww-browse-url) 1369(setopt browse-url-browser-function #'eww-browse-url)
1259 1370
1371(defcustom browse-url-safe-browser-functions nil
1372 "\"Safe\" browser functions."
1373 :type '(repeat-function))
1374
1375(defun browse-url-browser-function-safe-p (fn)
1376 "Return t if FN is a \"safe\" browser function."
1377 (memq fn (append browse-url-safe-browser-functions
1378 (mapcar (lambda (i)
1379 (plist-get (cdr i) :value))
1380 (seq-filter (lambda (i)
1381 (eq (car i) 'function-item))
1382 (cdr (get 'browse-url-browser-function
1383 'custom-type)))))))
1384
1385(put 'browse-url-browser-function 'safe-local-variable
1386 'browse-url-browser-function-safe-p)
1387
1260;;; EWW 1388;;; EWW
1261 1389
1262(setopt eww-use-browse-url ".") 1390(setopt eww-use-browse-url ".")
@@ -1266,6 +1394,15 @@ disconnect first."
1266 "~/Downloads")) 1394 "~/Downloads"))
1267(setopt eww-history-limit nil) 1395(setopt eww-history-limit nil)
1268 1396
1397(defun eww-readable/olivetti ()
1398 (interactive)
1399 (olivetti-mode +1)
1400 (eww-readable)
1401 (eww-reload t))
1402
1403(with-eval-after-load 'eww
1404 (keymap-set eww-mode-map "R" #'eww-readable/olivetti))
1405
1269;; Use Emacs bookmarks for EWW 1406;; Use Emacs bookmarks for EWW
1270(defun bookmark-eww--make () 1407(defun bookmark-eww--make ()
1271 "Make eww bookmark record." 1408 "Make eww bookmark record."
@@ -1322,9 +1459,9 @@ disconnect first."
1322 (hide-minor-mode 'browse-url-transform-mode)) 1459 (hide-minor-mode 'browse-url-transform-mode))
1323 1460
1324(with-eval-after-load 'browse-url-transform 1461(with-eval-after-load 'browse-url-transform
1325 (setopt eww-url-transformers 1462 (setq eww-url-transformers ; `setopt' causes a warning about custom-type
1326 '(eww-remove-tracking 1463 '(eww-remove-tracking
1327 browse-url-transform-url))) 1464 browse-url-transform-url)))
1328 1465
1329;; External browsers: firefox > chromium > chrome 1466;; External browsers: firefox > chromium > chrome
1330(setq browse-url-firefox-program 1467(setq browse-url-firefox-program
@@ -1347,6 +1484,36 @@ disconnect first."
1347 (browse-url-chrome-program #'browse-url-chrome) 1484 (browse-url-chrome-program #'browse-url-chrome)
1348 (t #'browse-url-default-browser))) 1485 (t #'browse-url-default-browser)))
1349 1486
1487(defmacro open-url-with (commandline &optional buffer error-buffer)
1488 (let ((buffer (or buffer " *open-url-with*"))
1489 (error-buffer (or error-buffer " *open-url-with/errors*")))
1490 `(lambda (url &rest _)
1491 (cl-letf (((alist-get ,buffer
1492 display-buffer-alist
1493 nil nil #'equal)
1494 '(display-buffer-no-window)))
1495 (async-shell-command (format ,commandline url)
1496 ,buffer
1497 ,error-buffer)))))
1498
1499(defun add-browse-url-handler (regexp opener)
1500 "Add OPENER to open REGEXP urls."
1501 (setf/assoc browse-url-handlers
1502 regexp
1503 opener))
1504
1505(add-browse-url-handler (rx (or (: ".pdf" eos)
1506 (: ".PDF" eos)))
1507 (open-url-with "zathura %s"))
1508(add-browse-url-handler (rx (or (: ".mp4" eos)
1509 "youtube.com"
1510 "piped.kavin.rocks"))
1511 (open-url-with "mpv %s"))
1512
1513(when (package-ensure 'elpher)
1514 (add-browse-url-handler (rx bos "gemini:")
1515 #'elpher-browse-url-elpher))
1516
1350;; Hinting at links 1517;; Hinting at links
1351(when (package-ensure 'link-hint) 1518(when (package-ensure 'link-hint)
1352 (setopt link-hint-avy-style 'at-full) 1519 (setopt link-hint-avy-style 'at-full)
@@ -1428,7 +1595,7 @@ NEW is passed to `eshell'."
1428 (pop-to-buffer buf) 1595 (pop-to-buffer buf)
1429 (eshell arg)) 1596 (eshell arg))
1430 ;; In the eshell buffer 1597 ;; In the eshell buffer
1431 (unless (equal default-directory dir) 1598 (unless (file-equal-p default-directory dir)
1432 (eshell/cd dir) 1599 (eshell/cd dir)
1433 (eshell-send-input) 1600 (eshell-send-input)
1434 (goto-char (point-max))))) 1601 (goto-char (point-max)))))
@@ -1438,7 +1605,9 @@ NEW is passed to `eshell'."
1438 (keymap-set eshell-mode-map "C-z" #'quit-window)) 1605 (keymap-set eshell-mode-map "C-z" #'quit-window))
1439 1606
1440(when (package-ensure 'eat) 1607(when (package-ensure 'eat)
1441 (add-hook 'eshell-first-time-mode-hook #'eat-eshell-mode)) 1608 (add-hook 'eshell-first-time-mode-hook #'eat-eshell-mode)
1609 (with-eval-after-load 'eat
1610 (keymap-unset eat-eshell-semi-char-mode-map "M-o" t)))
1442 1611
1443(when (package-ensure 'wiki-abbrev t) 1612(when (package-ensure 'wiki-abbrev t)
1444 (wiki-abbrev-insinuate) 1613 (wiki-abbrev-insinuate)
@@ -1448,7 +1617,8 @@ NEW is passed to `eshell'."
1448;;; Dinghie 1617;;; Dinghie
1449 1618
1450(add-to-list 'mode-line-misc-info 1619(add-to-list 'mode-line-misc-info
1451 '(buffer-ding-cookie buffer-ding-cookie) 1620 '(buffer-ding-cookie (:propertize buffer-ding-cookie
1621 face error))
1452 :append) 1622 :append)
1453 1623
1454(defvar buffer-ding-timer nil 1624(defvar buffer-ding-timer nil
@@ -1462,7 +1632,7 @@ NEW is passed to `eshell'."
1462 "Unflash the buffer after done `ding'ing." 1632 "Unflash the buffer after done `ding'ing."
1463 ;; (face-remap-remove-relative buffer-ding-cookie) 1633 ;; (face-remap-remove-relative buffer-ding-cookie)
1464 (setq buffer-ding-cookie nil) 1634 (setq buffer-ding-cookie nil)
1465 (force-mode-line-update)) 1635 (force-mode-line-update t))
1466 1636
1467(defun buffer-ding () 1637(defun buffer-ding ()
1468 "Flash the buffer for `ding'." 1638 "Flash the buffer for `ding'."
@@ -1481,6 +1651,9 @@ NEW is passed to `eshell'."
1481 (force-mode-line-update) 1651 (force-mode-line-update)
1482 (run-with-timer buffer-ding-timeout nil #'buffer-unding)))) 1652 (run-with-timer buffer-ding-timeout nil #'buffer-unding))))
1483 1653
1654;; (setopt ring-bell-function (lambda () (pulse-momentary-highlight-region
1655;; (window-start) (window-end))))
1656
1484(setopt ring-bell-function #'buffer-ding) 1657(setopt ring-bell-function #'buffer-ding)
1485(add-hook 'isearch-mode-end-hook #'buffer-unding) 1658(add-hook 'isearch-mode-end-hook #'buffer-unding)
1486 1659
@@ -1490,3 +1663,186 @@ NEW is passed to `eshell'."
1490 (when (or (null modes) 1663 (when (or (null modes)
1491 (apply #'derived-mode-p modes)) 1664 (apply #'derived-mode-p modes))
1492 (funcall fn))))) 1665 (funcall fn)))))
1666
1667;;; Flash!
1668
1669(defun flash-region@ (orig start end &rest args)
1670 (apply orig start end args)
1671 (pulse-momentary-highlight-region start end))
1672
1673(advice-add 'eval-region :around #'flash-region@)
1674(with-eval-after-load 'geiser
1675 (advice-add 'geiser-eval-region :around #'flash-region@))
1676
1677;;; KeepassXC Integration
1678
1679(when (package-ensure 'keepassxc-shim t)
1680 (keepassxc-shim-activate))
1681
1682;;; RCIRC
1683
1684(when (require 'rcirc)
1685 (setopt rcirc-default-full-name user-full-name)
1686 (setopt rcirc-default-user-name user-login-name)
1687 (setopt rcirc-authenticate-before-join t)
1688 (setopt rcirc-display-server-buffer nil)
1689 (setopt rcirc-buffer-maximum-lines 1000)
1690 (setopt rcirc-kill-channel-buffers t)
1691 (setopt rcirc-track-ignore-server-buffer-flag t)
1692
1693 ;; Theming
1694 (setopt rcirc-prompt "%t> ")
1695 (setopt rcirc-default-part-reason "See You Space Cowboy . . .")
1696 (setopt rcirc-default-quit-reason "(TLS connection improperly terminated)")
1697 (setopt rcirc-url-max-length 24)
1698 (setopt rcirc-response-formats
1699 '(("PRIVMSG" . "<%N> %m")
1700 ("NOTICE" . "-%N- %m")
1701 ("ACTION" . "* %N %m")
1702 ("COMMAND" . "%fs%m%f-")
1703 ("ERROR" . "%fw!!! %m")
1704 ("FAIL" . "(%fwFAIL%f-) %m")
1705 ("WARN" . "(%fwWARN%f-) %m")
1706 ("NOTE" . "(%fwNOTE%f-) %m")
1707 (t . "%fp*** %fs%n %r %m")))
1708
1709 (face-spec-set 'rcirc-nick-in-message-full-line
1710 '((t :foreground unspecified
1711 :background unspecified
1712 :weight unspecified
1713 :inherit nil)))
1714
1715 (add-to-list 'rcirc-omit-responses "NAMES")
1716
1717 (defun chat/setup ()
1718 (whitespace-mode -1)
1719 (electric-pair-local-mode -1)
1720 ;; IDK what's the deal with this
1721 (olivetti-mode +1)
1722 (visual-line-mode -1)
1723 (word-wrap-whitespace-mode +1))
1724
1725 (setq rcirc-debug-flag t)
1726
1727 (advice-add 'rcirc :after
1728 (defun enable-rcirc-track-minor-mode (&rest _)
1729 (rcirc-track-minor-mode 1)))
1730
1731 (add-hook 'rcirc-mode-hook #'chat/setup)
1732 (add-hook 'rcirc-mode-hook #'rcirc-omit-mode)
1733
1734 ;; "Fix" some things
1735 (setf rcirc-implemented-capabilities
1736 ;; I don't use these, and they mess up display in a few of my chats
1737 (delete "message-tags" rcirc-implemented-capabilities))
1738
1739 ;; Adding servers more better-er
1740 (defun rcirc-add-server (name &rest spec)
1741 "Add a server to `rcirc-server-alist' and `rcirc-authinfo' at once.
1742TODO: fully document"
1743 (let ((name* (if (plist-get spec :host)
1744 (plist-get spec :host)
1745 name))
1746 (nick (or (plist-get spec :nick)
1747 (bound-and-true-p rcirc-default-nick)
1748 (bound-and-true-p user-login-name)))
1749 (user-name (or (plist-get spec :user-name)
1750 (plist-get spec :user)
1751 (plist-get spec :nick)
1752 (bound-and-true-p rcirc-default-user-name)
1753 (bound-and-true-p rcirc-default-nick)
1754 (bound-and-true-p user-login-name)))
1755 (password (let ((password (or (plist-get spec :password)
1756 (plist-get spec :pass))))
1757 ;; (cond
1758 ;; ((functionp password) (funcall password))
1759 ;; ((stringp password) password))
1760 password
1761 )))
1762 ;; Add the server to `rcirc-server-alist'
1763 (setf (alist-get name* rcirc-server-alist nil nil #'equal)
1764 (append
1765 (list :nick nick
1766 :user-name user-name)
1767 (when password (list :password password))
1768 (when-let ((full-name (plist-get spec :full-name)))
1769 (list :full-name full-name))
1770 (when-let ((channels (plist-get spec :channels)))
1771 (list :channels channels))
1772 (when-let ((port (plist-get spec :port)))
1773 (list :port port))
1774 (when-let ((encryption (plist-get spec :encryption)))
1775 (list :encryption encryption))
1776 (when-let ((server-alias (or (plist-get spec :server-alias)
1777 (and (plist-get spec :host)
1778 name))))
1779 (list :server-alias server-alias))))
1780 ;; Add it to `rcirc-authinfo'
1781 (when-let ((auth (plist-get spec :auth)))
1782 (unless password (user-error "Trying to auth without a password"))
1783 (setf (alist-get name* rcirc-authinfo nil nil #'equal)
1784 (cl-case auth
1785 (nickserv (list 'nickserv nick password))
1786 (bitlbee (list 'bitlbee nick password))
1787 (quakenet (list 'quakenet user-name password))
1788 (sasl (list 'sasl user-name password))
1789 ;; (chanserv) ; These two aren't supported.
1790 ;; (certfp)
1791 (t (user-error "Unsupported :auth type `%s'"
1792 (plist-get plist :auth))))))
1793 ;; Return the server's name so that we don't leak authinfo
1794 name))
1795
1796 (defun rcirc-resolve-passwords (&rest _)
1797 (dolist-with-progress-reporter (s rcirc-server-alist)
1798 "Resolving lambda passwords in `rcirc-server-alist...'"
1799 (let ((pw (plist-get (cdr s) :password)))
1800 (setf (plist-get (cdr s) :password)
1801 (if (functionp pw) (funcall pw) pw))))
1802 (dolist-with-progress-reporter (i rcirc-authinfo)
1803 "Resolving lambda passwords in `rcirc-authinfo...'"
1804 (let ((pw (cadddr i)))
1805 (setf (cadddr i)
1806 (if-let ((s (assoc (car i) rcirc-server-alist)))
1807 (plist-get (cdr s) :password)
1808 (if (functionp pw) (funcall pw) pw))))))
1809
1810 (advice-add 'rcirc :before #'rcirc-resolve-passwords)
1811
1812 (defun rcirc/password (&rest spec)
1813 (lambda () (auth-info-password (car (apply #'auth-source-search spec)))))
1814
1815 (setq rcirc-server-alist nil)
1816
1817 (rcirc-add-server "tilde.town"
1818 :host "localhost" :port 6969
1819 :channels '("#tildetown" "#newbirc")
1820 :auth 'sasl
1821 :password
1822 (rcirc/password :host "localhost:6969" :user "acdw"))
1823 ;; (rcirc-add-server "43beans.casa"
1824 ;; :host "localhost" :port 6970
1825 ;; :channels '("#beans")
1826 ;; :auth nil
1827 ;; :password nil)
1828 (rcirc-add-server "tilde.chat"
1829 :host "irc.tilde.chat" :port 6697 :encryption 'tls
1830 ;; :channels left blank. There's some kind of race
1831 ;; condition in SASL and identd that means I authenticate
1832 ;; before being fully authenticated? Or something.
1833 ;; Tilde.chat's NickServ does autojoin, though, so that
1834 ;; works out without an afternoon of debugging.
1835 :auth 'sasl
1836 :password (rcirc/password :host "tilde.chat" :user "acdw"))
1837 (rcirc-add-server "m455.casa"
1838 :port 6697 :encryption 'tls
1839 :channels '("#basement" "#43beans")
1840 :auth 'sasl
1841 :password (rcirc/password :host "m455.casa" :user "acdw"))
1842 (rcirc-add-server "libera.chat"
1843 :host "irc.libera.chat" :port 6697 :encryption 'tls
1844 :channels '("#emacs" "#rcirc")
1845 :auth 'sasl
1846 :password (rcirc/password :host "libera.chat" :user "acdw"))
1847 ;; End of rcirc configuration.
1848 )
diff --git a/user-dirs.dirs b/user-dirs.dirs index 385533d..55d1c70 100644 --- a/user-dirs.dirs +++ b/user-dirs.dirs
@@ -1,16 +1,15 @@
1# -*- sh -*-
2# This file is written by xdg-user-dirs-update 1# This file is written by xdg-user-dirs-update
3# If you want to change or add directories, just edit the line you're 2# If you want to change or add directories, just edit the line you're
4# interested in. All local changes will be retained on the next run. 3# interested in. All local changes will be retained on the next run.
5# Format is XDG_xxx_DIR="$HOME/yyy", where yyy is a shell-escaped 4# Format is XDG_xxx_DIR="$HOME/yyy", where yyy is a shell-escaped
6# homedir-relative path, or XDG_xxx_DIR="/yyy", where /yyy is an 5# homedir-relative path, or XDG_xxx_DIR="/yyy", where /yyy is an
7# absolute path. No other format is supported. 6# absolute path. No other format is supported.
8# 7#
9XDG_DESKTOP_DIR="$HOME/var/desk" 8XDG_DESKTOP_DIR="$HOME/var/desk"
10XDG_DOCUMENTS_DIR="$HOME/var/doc" 9XDG_DOCUMENTS_DIR="$HOME/var/doc"
11XDG_DOWNLOAD_DIR="$HOME/var/download" 10XDG_DOWNLOAD_DIR="$HOME/var/download"
12XDG_MUSIC_DIR="$HOME/var/music" 11XDG_MUSIC_DIR="$HOME/var/music"
13XDG_PICTURES_DIR="$HOME/var/img" 12XDG_PICTURES_DIR="$HOME/var/img"
14XDG_PUBLICSHARE_DIR="$HOME/var/public" 13XDG_PUBLICSHARE_DIR="$HOME/"
15XDG_TEMPLATES_DIR="$HOME/var/templ" 14XDG_TEMPLATES_DIR="$HOME/"
16XDG_VIDEOS_DIR="$HOME/var/video" 15XDG_VIDEOS_DIR="$HOME/var/video"