diff options
-rw-r--r-- | bash/functions.bash | 216 | ||||
-rw-r--r-- | bash/history.bash | 2 | ||||
-rw-r--r-- | chicken/csirc | 8 | ||||
-rw-r--r-- | emacs.el | 704 | ||||
-rw-r--r-- | user-dirs.dirs | 7 |
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 | ||
3 | memq() { # memq ITEM ARRAY | 3 | memq() { # 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 | ||
16 | rebashrc() { # rebashrc | 16 | rebashrc() { # 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 | ||
26 | first_which() { # first_which COMMAND... | 26 | first_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 | ||
35 | please() { # please [COMMAND...] | 35 | please() { # 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 | ||
48 | mkcd() { | 48 | mkcd() { |
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 | } |
67 | alias cd='mkcd ' | 67 | alias 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' |
71 | julian() { | 71 | julian() { |
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 |
76 | f() { | 76 | f() { |
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 | ||
83 | words() { | 83 | words() { |
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 | ||
87 | if ! command -v dict >/dev/null 2>&1; then | 88 | if ! 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 | } |
91 | fi | 92 | fi |
92 | 93 | ||
93 | if command -v thesauracles >/dev/null 2>&1; then | 94 | if 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 | } |
100 | fi | 101 | fi |
101 | 102 | ||
102 | up() { | 103 | up() { |
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 | ||
143 | apk() { # wrapper for apk(1) | 144 | apk() { # 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 | |||
165 | p() { | ||
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 |
30 | HISTIGNORE='&:[ ]*' | 30 | HISTIGNORE='&:[ ]*' |
31 | # Other commands to ignore | 31 | # Other commands to ignore |
32 | HISTIGNORE="$HISTIGNORE:ls:exit:cd" | 32 | HISTIGNORE="$HISTIGNORE:ls:exit:cd:p" |
33 | 33 | ||
34 | # Automatically append to HISTFILE on every command | 34 | # Automatically append to HISTFILE on every command |
35 | PROMPT_COMMAND="history -a; ${PROMPT_COMMAND:-:}" | 35 | PROMPT_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. |
16 | If LOCAL is t, add ~/src/PKG.el to `load-path' and generate autoloads. | 17 | PKG can be a symbol, a string, or a list. A symbol will be |
17 | If REQUIRE is non-nil, require it as well." | 18 | installed using `package-install' from `package-archives'. A |
19 | string will use `package-vc-install', which see. If given a | ||
20 | list, it will be interpreted as a full set of arguments to one of | ||
21 | the above functions, depending on the type of its car. | ||
22 | |||
23 | If LOCAL is t, add ~/src/PKG.el to `load-path' and generate | ||
24 | autoloads. If LOCAL is a string, Add that directory to | ||
25 | `load-path'. | ||
26 | |||
27 | If 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. |
444 | Good to use for :around advice." | 499 | Good 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. |
1208 | If called with ARG non-nil, or with \\[universal-argument], | 1319 | ;; If called with ARG non-nil, or with \\[universal-argument], |
1209 | disconnect 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. | ||
1742 | TODO: 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 | # |
9 | XDG_DESKTOP_DIR="$HOME/var/desk" | 8 | XDG_DESKTOP_DIR="$HOME/var/desk" |
10 | XDG_DOCUMENTS_DIR="$HOME/var/doc" | 9 | XDG_DOCUMENTS_DIR="$HOME/var/doc" |
11 | XDG_DOWNLOAD_DIR="$HOME/var/download" | 10 | XDG_DOWNLOAD_DIR="$HOME/var/download" |
12 | XDG_MUSIC_DIR="$HOME/var/music" | 11 | XDG_MUSIC_DIR="$HOME/var/music" |
13 | XDG_PICTURES_DIR="$HOME/var/img" | 12 | XDG_PICTURES_DIR="$HOME/var/img" |
14 | XDG_PUBLICSHARE_DIR="$HOME/var/public" | 13 | XDG_PUBLICSHARE_DIR="$HOME/" |
15 | XDG_TEMPLATES_DIR="$HOME/var/templ" | 14 | XDG_TEMPLATES_DIR="$HOME/" |
16 | XDG_VIDEOS_DIR="$HOME/var/video" | 15 | XDG_VIDEOS_DIR="$HOME/var/video" |