diff options
Diffstat (limited to 'basics.el')
-rw-r--r-- | basics.el | 376 |
1 files changed, 376 insertions, 0 deletions
diff --git a/basics.el b/basics.el new file mode 100644 index 0000000..06f5ece --- /dev/null +++ b/basics.el | |||
@@ -0,0 +1,376 @@ | |||
1 | ;;; basics.el --- Super basic Emacs settings -*- lexical-binding: t -*- | ||
2 | |||
3 | ;;; Commentary: | ||
4 | |||
5 | ;; These are the settings that I literally cannot live without. Basic | ||
6 | ;; settings, built-in packages, that kind of stuff. Everything else | ||
7 | ;; goes in init.el. | ||
8 | |||
9 | ;;; Code: | ||
10 | |||
11 | ;;; Directories | ||
12 | |||
13 | (defmacro defdir (name directory &optional docstring makedir) | ||
14 | "Define a variable and a function NAME expanding to DIRECTORY. | ||
15 | DOCSTRING is applied to the variable; its default is DIRECTORY's | ||
16 | path. If MAKEDIR is non-nil, the directory and its parents will | ||
17 | be created." | ||
18 | (declare (indent 2) (doc-string 3)) | ||
19 | `(progn | ||
20 | (defvar ,name (expand-file-name ,directory) | ||
21 | ,(concat (or docstring (format "%s" directory)) "\n" | ||
22 | "Defined by `defdir'.")) | ||
23 | (defun ,name (file &optional mkdir) | ||
24 | ,(concat "Expand FILE relative to variable `" (symbol-name name) "'.\n" | ||
25 | "If MKDIR is non-nil, parent directories are created.\n" | ||
26 | "Defined by `defdir'.") | ||
27 | (let ((file-name (expand-file-name | ||
28 | (convert-standard-filename file) ,name))) | ||
29 | (when mkdir | ||
30 | (make-directory (file-name-directory file-name) :parents)) | ||
31 | file-name)) | ||
32 | ,(if makedir | ||
33 | `(make-directory ,directory :parents) | ||
34 | `(unless (file-exists-p ,directory) | ||
35 | (warn "Directory `%s' doesn't exist." ,directory))))) | ||
36 | |||
37 | (defdir etc/ (locate-user-emacs-file "etc/") | ||
38 | "Where various Emacs files are placed." | ||
39 | :makedir) | ||
40 | |||
41 | (defdir lisp/ (locate-user-emacs-file "lisp/") | ||
42 | "My bespoke elisp files." | ||
43 | :makedir) | ||
44 | (push lisp/ load-path) | ||
45 | |||
46 | (defdir sync/ "~/Sync/" | ||
47 | "My Syncthing directory." | ||
48 | :makedir) | ||
49 | |||
50 | (defdir private/ (sync/ "emacs/private/") | ||
51 | "Private files and stuff." | ||
52 | :makedir) | ||
53 | (push private/ load-path) | ||
54 | |||
55 | (use-package no-littering | ||
56 | :ensure t :demand t | ||
57 | :preface | ||
58 | (setq-default no-littering-etc-directory etc/ | ||
59 | no-littering-var-directory etc/)) | ||
60 | |||
61 | ;;; Settings | ||
62 | |||
63 | ;; Async | ||
64 | (setq-default async-shell-command-buffer 'new-buffer | ||
65 | async-shell-command-display-buffer nil) | ||
66 | |||
67 | ;; Scrolling | ||
68 | (setq-default auto-hscroll-mode t | ||
69 | auto-window-vscroll nil | ||
70 | fast-but-imprecise-scrolling t | ||
71 | hscroll-margin 1 | ||
72 | hscroll-step 1 | ||
73 | scroll-conservatively 25 | ||
74 | scroll-margin 0 | ||
75 | scroll-preserve-screen-position 1 | ||
76 | scroll-step 1) | ||
77 | (scroll-bar-mode -1) | ||
78 | (horizontal-scroll-bar-mode -1) | ||
79 | (pixel-scroll-precision-mode) | ||
80 | |||
81 | ;; Cursor | ||
82 | (setq-default cursor-in-non-selected-windows 'hollow | ||
83 | cursor-type 'bar | ||
84 | blink-cursor-blinks 1 | ||
85 | blink-cursor-interval 0.25 | ||
86 | blink-cursor-delay 0.25) | ||
87 | (blink-cursor-mode) | ||
88 | |||
89 | ;; Mouse | ||
90 | (setq-default mouse-drag-copy-region t | ||
91 | mouse-wheel-progressive-speed nil | ||
92 | mouse-yank-at-point t) | ||
93 | |||
94 | ;; Dialogs | ||
95 | (unless (boundp 'use-short-answers) | ||
96 | (fset 'yes-or-no-p 'y-or-n-p)) | ||
97 | |||
98 | (setq-default read-answer-short t | ||
99 | use-dialog-box nil | ||
100 | use-file-dialog nil | ||
101 | use-short-answers t) | ||
102 | |||
103 | ;; Minibuffer | ||
104 | (setq-default completion-ignore-case t | ||
105 | read-buffer-completion-ignore-case t | ||
106 | read-file-name-completion-ignore-case t | ||
107 | completions-detailed t | ||
108 | enable-recursive-minibuffers t | ||
109 | file-name-shadow-properties '(invisible t intangible t) | ||
110 | minibuffer-eldef-shorten-default t | ||
111 | minibuffer-prompt-properties '( read-only t | ||
112 | cursor-intangible t | ||
113 | face minibuffer-prompt)) | ||
114 | (file-name-shadow-mode) | ||
115 | (minibuffer-electric-default-mode) | ||
116 | |||
117 | (require 'savehist) | ||
118 | (setq-default history-length 1024 | ||
119 | history-delete-duplicates t | ||
120 | ;; savehist-file (etc/ "savehist.el") | ||
121 | savehist-save-minibuffer-history t | ||
122 | savehist-autosave-interval 30) | ||
123 | (savehist-mode) | ||
124 | |||
125 | ;; Undo | ||
126 | (setq-default undo-limit (* 10 1024 1024)) | ||
127 | |||
128 | ;; Killing and yanking | ||
129 | (setq-default kill-do-not-save-duplicates t | ||
130 | kill-read-only-ok t | ||
131 | save-interprogram-paste-before-kill t | ||
132 | yank-pop-change-selection t) | ||
133 | (delete-selection-mode) | ||
134 | |||
135 | ;; Notifying the user | ||
136 | (setq-default echo-keystrokes 0.01 | ||
137 | ring-bell-function #'ignore) | ||
138 | |||
139 | ;; Point and mark | ||
140 | (setq-default set-mark-command-repeat-pop t) | ||
141 | |||
142 | ;; The system | ||
143 | (setq-default read-process-output-max (* 10 1024 1024)) | ||
144 | |||
145 | ;; Startup | ||
146 | (setq-default inhibit-startup-screen t | ||
147 | initial-buffer-choice t | ||
148 | initial-scratch-message nil) | ||
149 | |||
150 | ;; (menu-bar-mode -1) | ||
151 | (tool-bar-mode -1) | ||
152 | (tooltip-mode -1) | ||
153 | |||
154 | ;; Text editing | ||
155 | (setq-default fill-column 80 | ||
156 | sentence-end-double-space t | ||
157 | tab-width 8) | ||
158 | (global-so-long-mode) | ||
159 | |||
160 | (setq-default show-paren-delay 0.01 | ||
161 | show-paren-style 'parenthesis | ||
162 | show-paren-when-point-in-periphery t | ||
163 | show-paren-when-point-inside-paren t) | ||
164 | (show-paren-mode) | ||
165 | (electric-pair-mode) | ||
166 | |||
167 | ;; Encodings | ||
168 | (set-language-environment "UTF-8") | ||
169 | (setq-default buffer-file-coding-system 'utf-8-unix | ||
170 | coding-system-for-read 'utf-8-unix | ||
171 | coding-system-for-write 'utf-8-unix | ||
172 | default-process-coding-system '(utf-8-unix . utf-8-unix) | ||
173 | locale-coding-system 'utf-8-unix) | ||
174 | (set-charset-priority 'unicode) | ||
175 | (prefer-coding-system 'utf-8-unix) | ||
176 | (set-default-coding-systems 'utf-8-unix) | ||
177 | (set-terminal-coding-system 'utf-8-unix) | ||
178 | (set-keyboard-coding-system 'utf-8-unix) | ||
179 | (pcase system-type | ||
180 | ((or 'ms-dos 'windows-nt) | ||
181 | (set-clipboard-coding-system 'utf-16-le) | ||
182 | (set-selection-coding-system 'utf-16-le)) | ||
183 | (_ | ||
184 | (set-selection-coding-system 'utf-8) | ||
185 | (set-clipboard-coding-system 'utf-8))) | ||
186 | |||
187 | ;; Abbrev | ||
188 | (setq-default abbrev-file-name (sync/ "abbrev.el") | ||
189 | save-abbrevs 'silently) | ||
190 | |||
191 | ;; Files | ||
192 | (setq-default auto-revert-verbose nil | ||
193 | global-auto-revert-non-file-buffers t | ||
194 | create-lockfiles nil | ||
195 | find-file-visit-truename t | ||
196 | mode-require-final-newline t | ||
197 | view-read-only t | ||
198 | save-silently t) | ||
199 | (global-auto-revert-mode) | ||
200 | |||
201 | (setq-default auto-save-default nil | ||
202 | auto-save-interval 1 | ||
203 | auto-save-no-message t | ||
204 | auto-save-timeout 1 | ||
205 | auto-save-visited-interval 1) | ||
206 | (add-to-list 'auto-save-file-name-transforms | ||
207 | `(".*" ,(etc/ "auto-save/" t) t)) | ||
208 | (auto-save-visited-mode) | ||
209 | |||
210 | (setq-default backup-by-copying t | ||
211 | version-control t | ||
212 | kept-new-versions 8 | ||
213 | kept-old-versions 8 | ||
214 | delete-old-versions t) | ||
215 | |||
216 | (require 'recentf) | ||
217 | (setq-default ;; recentf-save-file (etc/ "recentf" t) | ||
218 | recentf-max-menu-items 500 | ||
219 | recentf-max-saved-items nil ; Save the whole list | ||
220 | recentf-auto-cleanup 'mode) | ||
221 | (add-to-list 'recentf-exclude etc/) | ||
222 | (add-to-list 'recentf-exclude "-autoloads.el\\'") | ||
223 | (add-hook 'buffer-list-update-hook #'recentf-track-opened-file) | ||
224 | (recentf-mode) | ||
225 | |||
226 | (require 'saveplace) | ||
227 | (setq-default ;; save-place-file (etc/ "places.el") | ||
228 | save-place-forget-unreadable-files (eq system-type | ||
229 | 'gnu/linux)) | ||
230 | (save-place-mode) | ||
231 | |||
232 | (require 'uniquify) | ||
233 | (setq uniquify-after-kill-buffer-p t | ||
234 | uniquify-buffer-name-style 'forward | ||
235 | uniquify-ignore-buffers-re "^\\*" | ||
236 | uniquify-separator path-separator) | ||
237 | |||
238 | (setq-local vc-follow-symlinks t | ||
239 | vc-make-backup-files t) | ||
240 | |||
241 | ;; Native compilation | ||
242 | (setq-default native-comp-async-report-warnings-errors 'silent | ||
243 | native-comp-deferred-compilation t | ||
244 | native-compile-target-directory (etc/ "eln" t)) | ||
245 | (add-to-list 'native-comp-eln-load-path native-compile-target-directory) | ||
246 | (when (fboundp 'startup-redirect-eln-cache) | ||
247 | (startup-redirect-eln-cache native-compile-target-directory)) | ||
248 | |||
249 | ;; Custom file | ||
250 | (setq-default custom-file (sync/ "emacs/custom.el")) | ||
251 | (define-advice package--save-selected-packages (:around (orig &rest args) no-custom) | ||
252 | "Don't save `package-selected-packages' to `custom-file'." | ||
253 | (let ((custom-file null-device)) | ||
254 | (apply orig args))) | ||
255 | |||
256 | ;; Goto Address | ||
257 | (if (fboundp 'global-goto-address-mode) | ||
258 | (global-goto-address-mode) | ||
259 | (add-hook 'after-change-major-mode-hook #'goto-address-mode)) | ||
260 | |||
261 | ;; Winner | ||
262 | (winner-mode) | ||
263 | |||
264 | ;;; Keybindings | ||
265 | |||
266 | (defun other-window|switch-buffer (arg) | ||
267 | "Call `other-window' or `switch-buffer' depending on windows. | ||
268 | When called with prefix ARG, unconditionally switch buffer." | ||
269 | (interactive "P") | ||
270 | (if (or arg (one-window-p)) | ||
271 | (switch-to-buffer (other-buffer) nil t) | ||
272 | (other-window 1))) | ||
273 | |||
274 | (defun delete-window|bury-buffer () | ||
275 | "Delete the current window, or bury the current buffer. | ||
276 | If the current window is the only window, bury the buffer." | ||
277 | (interactive) | ||
278 | (condition-case e | ||
279 | (delete-window) | ||
280 | (t (bury-buffer)))) | ||
281 | |||
282 | (defun +cycle-spacing (&optional n) | ||
283 | ;; `cycle-spacing' is wildly different in 29.1 over 28. | ||
284 | "Negate N argument on `cycle-spacing'. | ||
285 | That is, with a positive N, deletes newlines as well, leaving -N | ||
286 | spaces. If N is negative, it will not delete newlines and leave | ||
287 | N spaces." | ||
288 | (interactive "*p") | ||
289 | (cycle-spacing (- n))) | ||
290 | |||
291 | (global-set-key [remap eval-expression] #'pp-eval-expression) | ||
292 | (global-set-key (kbd "M-o") #'other-window|switch-buffer) | ||
293 | (global-set-key (kbd "C-x 0") #'delete-window|bury-buffer) | ||
294 | (global-set-key (kbd "M-SPC") #'+cycle-spacing) | ||
295 | (global-set-key (kbd "C-x C-k") #'kill-this-buffer) | ||
296 | |||
297 | ;;; Hooks | ||
298 | |||
299 | (add-hook 'after-save-hook #'executable-make-buffer-file-executable-if-script-p) | ||
300 | (add-hook 'find-file-not-found-functions | ||
301 | (defun create-missing-directories () | ||
302 | "Automatically create missing directories." | ||
303 | (let ((target-dir (file-name-directory buffer-file-name))) | ||
304 | (unless (file-exists-p target-dir) | ||
305 | (make-directory target-dir :parents))))) | ||
306 | (add-hook 'find-file-hook | ||
307 | (defun vc-remote-off () | ||
308 | "Turn VC off when remote." | ||
309 | (when (file-remote-p (buffer-file-name)) | ||
310 | (setq-local vc-handled-backends nil)))) | ||
311 | |||
312 | ;;; Advice | ||
313 | |||
314 | (define-advice switch-to-buffer (:after (&rest _) normal-mode) | ||
315 | "Automatically determine the mode for non-file buffers." | ||
316 | (when-let ((_ (and (eq major-mode 'fundamental-mode))) | ||
317 | (buffer-file-name (buffer-name))) | ||
318 | (normal-mode))) | ||
319 | |||
320 | (define-advice canonically-space-region | ||
321 | (:around (orig &rest args) double-space-sentences) | ||
322 | "Always double-space sentences canonically." | ||
323 | (let ((sentence-end-double-space t)) | ||
324 | (apply orig args))) | ||
325 | |||
326 | ;; With region or ... | ||
327 | (defun advise-region-or-buffer (&rest _) | ||
328 | "`:before' advice to work on the active region or whole buffer. | ||
329 | See also `with-region-or-buffer'." | ||
330 | (interactive (if mark-active | ||
331 | (list (region-beginning) (region-end)) | ||
332 | (list (point-min) (point-max))))) | ||
333 | |||
334 | (defun advise-region-or-line (&rest _) | ||
335 | "`:before' advice to work on the active region or whole line. | ||
336 | See also `with-region-or-line'." | ||
337 | (interactive (if mark-active | ||
338 | (list (region-beginning) (region-end)) | ||
339 | (list (line-beginning-position) (line-end-position))))) | ||
340 | |||
341 | (defun advise-region-or-to-eol (&rest _) | ||
342 | "`:before' advice to work on the active region or to end of line. | ||
343 | See also `with-region-or-to-eol'." | ||
344 | (INTERACTIVE (if mark-active | ||
345 | (list (region-beginning) (region-end)) | ||
346 | (list (point) (line-end-position))))) | ||
347 | |||
348 | (defmacro with-region-or-buffer (&rest funcs) | ||
349 | "Advise FUNCS with `advise-region-or-buffer'." | ||
350 | `(progn | ||
351 | ,@(cl-loop for fn in funcs | ||
352 | collect | ||
353 | `(advice-add ',fn :before #'advise-region-or-buffer)))) | ||
354 | |||
355 | (defmacro with-region-or-line (&rest funcs) | ||
356 | "Advise FUNCS with `advise-region-or-line'." | ||
357 | `(progn | ||
358 | ,@(cl-loop for fn in funcs | ||
359 | collect | ||
360 | `(advice-add ',fn :before #'advise-region-or-line)))) | ||
361 | |||
362 | (defmacro with-region-or-to-eol (&rest funcs) | ||
363 | "Advise FUNCS with `advise-region-or-to-eol'." | ||
364 | `(progn | ||
365 | ,@(cl-loop for fn in funcs | ||
366 | collect | ||
367 | `(advice-add ',fn :before #'advise-region-or-to-eol)))) | ||
368 | |||
369 | (with-region-or-buffer indent-region) | ||
370 | |||
371 | ;;; Packages | ||
372 | |||
373 | (use-package _acdw | ||
374 | :load-path private/) | ||
375 | |||
376 | ;;; basics.el ends here | ||