summaryrefslogtreecommitdiff
path: root/lisp/core.el
blob: 34f9817c693c70c1ba073021bda1eefcc3c68b4e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
;;; core.el -*- lexical-binding: t; -*-
;;;
;;; Author:  Jakob L. Kreuze <zerodaysfordays@sdf.org>
;;; URL:     https://git.sr.ht/~jakob/.emacs.d/
;;;
;;; Configuration for the "core" behavior of GNU Emacs. Generally, anything
;;; which does not involve a third-party package.
;;;



;; [HACK] Use the correct `emacsclient' binary on Gentoo.
(when (cl-search "28" (emacs-version))
  (setq with-editor-emacsclient-executable "emacsclient-emacs-28-vcs"))

;; Having Emacs open to `*scratch*' feels as though it's inviting me to punch
;; out some Lisp forms and evaluate them. I like to pretend that my computers
;; are Lisp machines.

;; TODO: Replace with dashboard.el?

(setq inhibit-startup-message t
      inhibit-startup-buffer-menu t
      initial-scratch-message nil
      initial-buffer-choice nil)

;; A recurring theme in this configuration file is changing where Emacs packages
;; drop their various state files. 'no-littering.el' is a package that handles
;; this by creating 'var/' and 'etc/' directories in the Emacs directory, but
;; it's implemented in a way that pollutes the global namespace with variables
;; for packages that I don't use, and would require a significant amount of
;; configuration on my part anyway, so I've decided to do this manually, setting
;; relevant variables to subdirectories of XDG_CACHE_HOME and XDG_DATA_HOME.

;; Save backup files to one directory instead of making a mess of the filesystem.

(setq backup-directory-alist `(("." . "~/.cache/emacs")))

;; `auto-save', in addition to the actual files it saves, maintains another file
;; listing the files it's currently taking care of.

(setq auto-save-list-file-prefix "~/.cache/emacs/auto-save-list/.saves-")

;; Disable the creation of locking symlinks in the current directory. This is a
;; very opinionated choice, and probably isn't a good idea for most.

(setq create-lockfiles nil)

;; I don't use 'custom.el' to set variables, but a few of the packages I use do.
;; This snippet ensures that a massacre is not made of my init.el.

(setq custom-file "~/.emacs.d/custom.el")
(when (file-exists-p custom-file)
  (load custom-file))

;; I don't really care about persisting minibuffer history between sessions.
;; Even if I disable `savehist-mode', it still writes to disk, so the least I
;; can do is move the history file to somewhere that isn't .emacs.d.

(savehist-mode -1)
(setq savehist-file "~/.cache/emacs/history")

(use-package tramp
  :straight nil
  :init
  (setq tramp-backup-directory-alist backup-directory-alist)
  (setq-default tramp-persistency-file-name "~/.cache/emacs/tramp"))

(use-package nsm
  :straight nil
  :init
  (setq nsm-settings-file "~/.cache/emacs/network-security.data"))

;; Use a consistent confirmation dialog of "y or n".

(fset 'yes-or-no-p 'y-or-n-p)

;; Automatically revert buffers and dired listings when something on disk
;; changes.

(use-package autorevert
  :config
  (global-auto-revert-mode 1)
  (setq global-auto-revert-non-file-buffers t
        auto-revert-verbose nil))

;; "Command attempted to use minibuffer while in minibuffer" gets old fast.

(setq enable-recursive-minibuffers t)

;; Select help windows when I pop them so that I can kill them with <q>.

(setq help-window-select t)

;; Most *NIX tools work best when files are terminated with a newline.

(setq require-final-newline t)

;; Sentences should be separated by a single space. Treat two sentences as such
;; when filling.

(setq sentence-end-double-space nil)

;; I use the tab key, but I generally prefer space characters to tabstops and
;; like a four-character width for indentation.

(setq-default indent-tabs-mode nil
              tab-width 4)

;; Modern conventions state that 80 characters is the standard width.

(setq-default fill-column 80)

;; When killing, add whatever's in the system clipboard if it isn't there
;; already, so I can get it back with <M-y>.

(setq save-interprogram-paste-before-kill t)

;; Enable the default-disabled functions that I use.

(put 'downcase-region 'disabled nil)
(put 'upcase-region 'disabled nil)

;; Enable useful visual queues.

(column-number-mode t)

;; Unbind <C-z> and <C-x C-z> so that I'm not accidentally calling =suspend-frame=.

(global-unset-key (kbd "C-z"))
(global-unset-key (kbd "C-x C-z"))

;; Replace `kill-word', `backward-kill-word', and `kill-visual-line' with
;; equivalents that do not copy the region into the kill ring.

(defun delete-word (arg)
  "Delete characters forward until encountering the end of a word.
With argument ARG, do this that many times."
  (interactive "p")
  (delete-region (point) (progn (forward-word arg) (point))))

(defun backward-delete-word (arg)
    "Delete characters backward until encountering the beginning of a word.
With argument ARG, do this that many times."
  (interactive "p")
  (delete-word (- arg)))

(defun delete-visual-line (&optional arg)
  "Delete the rest of the visual line.
With prefix argument ARG, delete that many visual lines from point.
If ARG is negative, delete visual lines backward.
If ARG is zero, delete the text before point on the current visual
line."
  (interactive "P")
  ;; Like in `kill-line', it's better to move point to the other end
  ;; of the kill before killing.
  (let ((opoint (point))
        (delete-whole-line (and kill-whole-line (bolp))))
    (if arg
        (vertical-motion (prefix-numeric-value arg))
      (end-of-visual-line 1)
      (if (= (point) opoint)
          (vertical-motion 1)
        ;; Skip any trailing whitespace at the end of the visual line.
        ;; We used to do this only if `show-trailing-whitespace' is
        ;; nil, but that's wrong; the correct thing would be to check
        ;; whether the trailing whitespace is highlighted.  But, it's
        ;; OK to just do this unconditionally.
        (skip-chars-forward " \t")))
    (delete-region opoint (if (and delete-whole-line (= (following-char) ?\n))
                              (1+ (point))
                            (point)))))

(bind-key "M-d" #'delete-word)
(bind-key "M-DEL" #'backward-delete-word)
(bind-key "C-k" #'delete-visual-line)

;; I use <M-v> and <M-V> for movement, mostly, so having <prior> and <next>
;; bound to the same functions is a little redundant. What I prefer is to bind
;; them to functions for scolling by one line at a time instead. Sometimes
;; useful when perusing IRC logs.

(define-minor-mode baby-scroll-mode
  "Toggle `baby-scroll-mode'.
Minor mode which remaps <next> and <prior> to less extreme
scrolling functions."
  :global t
  nil "Baby Scroll" '(([next] . scroll-up-line)
                      ([prior] . scroll-down-line)))

(baby-scroll-mode)

;; Don't do jerky jumps when the cursor reaches the end of the window. Instead,
;; just scroll by one line.

(setq scroll-conservatively most-positive-fixnum)

© 2015 - 2026 Jakob L. Kreuze