changeset 187: | a962648ad6d5 |
parent: | 0e972410eb3e |
child: | 34bacb513d55 |
author: | Richard Westhaver <ellis@rwest.io> |
date: | Fri, 02 Feb 2024 15:52:37 -0500 |
permissions: | -rw-r--r-- |
description: | add dir-locals and eglot-x |
21 | 1 | ;;; default.el --- default config -*- lexical-binding: t -*- |
27 | 2 | |
3 | ;;; Code: |
|
30 | 4 | ;;; Settings |
21 | 5 | (put 'upcase-region 'disabled nil) |
30 | 6 | (put 'list-threads 'disabled nil) |
7 | (put 'list-timers 'disabled nil) |
|
34 | 8 | (setq show-paren-context-when-offscreen 'overlay) |
9 | (setopt |
|
10 | ;; tabs = bad |
|
11 | indent-tabs-mode nil |
|
31 | 12 | make-backup-files nil |
13 | auto-save-list-file-prefix (expand-file-name "auto-save/." user-emacs-directory) |
|
14 | tramp-auto-save-directory (expand-file-name "auto-save/tramp/" user-emacs-directory) |
|
15 | dired-free-space nil |
|
34 | 16 | mml-attach-file-at-the-end t |
17 | dired-mouse-drag-files t |
|
31 | 18 | confirm-kill-emacs nil |
19 | confirm-kill-processes nil |
|
20 | use-short-answers t |
|
21 | display-time-format "%Y-%m-%d %H:%M" |
|
22 | ring-bell-function 'ignore |
|
23 | completion-ignore-case t |
|
33 | 24 | ;; NOTE 2023-11-04: you need to add the following lines to ~/.gnupg/gpg-agent.conf: |
25 | ;; allow-emacs-pinentry |
|
26 | ;; allow-loopback-pinentry |
|
41 | 27 | epg-pinentry-mode 'loopback |
31 | 28 | shr-use-colors nil |
29 | shr-use-fonts nil |
|
30 | shr-max-image-proportion 0.6 |
|
31 | shr-image-animate nil |
|
32 | shr-discard-aria-hidden t |
|
33 | bookmark-default-file (expand-file-name "bookmarks" user-emacs-directory) |
|
34 | project-list-file (expand-file-name "projects" user-emacs-directory) |
|
148
0d9d5cd46af5
added net/stream.rs, change def-ts-lang to macrolet form
ellis <ellis@rwest.io>
parents:
126
diff
changeset
|
35 | project-mode-line t |
0d9d5cd46af5
added net/stream.rs, change def-ts-lang to macrolet form
ellis <ellis@rwest.io>
parents:
126
diff
changeset
|
36 | project-file-history-behavior 'relativize |
31 | 37 | emms-directory (expand-file-name "emms" user-emacs-directory) |
38 | gnus-cache-directory (expand-file-name "gnus" user-emacs-directory) |
|
39 | url-cache-directory (expand-file-name "url" user-emacs-directory) |
|
40 | tab-always-indent 'complete |
|
41 | shr-cookie-policy nil |
|
34 | 42 | ;; NOTE 2023-11-04: EXPERIMENTAL |
148
0d9d5cd46af5
added net/stream.rs, change def-ts-lang to macrolet form
ellis <ellis@rwest.io>
parents:
126
diff
changeset
|
43 | ediff-floating-control-frame t |
0d9d5cd46af5
added net/stream.rs, change def-ts-lang to macrolet form
ellis <ellis@rwest.io>
parents:
126
diff
changeset
|
44 | register-use-preview nil |
34 | 45 | shr-use-xwidgets-for-media t |
31 | 46 | browse-url-browser-function 'browse-url-default-browser |
34 | 47 | eww-auto-rename-buffer 'title |
31 | 48 | eww-search-prefix "https://duckduckgo.com/html?q=" |
34 | 49 | view-read-only t) |
27 | 50 | |
30 | 51 | ;;; Variables |
33 | 52 | (defvar user-custom-file (expand-file-name (format "%s.el" user-login-name) user-emacs-directory)) |
32 | 53 | (defvar user-home-directory (expand-file-name "~")) |
54 | (defvar user-lab-directory (expand-file-name "lab" user-home-directory)) |
|
55 | (defvar user-stash-directory (expand-file-name "stash" user-home-directory)) |
|
56 | (defvar user-store-directory (expand-file-name "store" user-home-directory)) |
|
57 | (defvar user-shed-directory (expand-file-name "shed" user-home-directory)) |
|
58 | (defvar user-mail-directory (expand-file-name "mail" user-home-directory)) |
|
59 | (defvar user-media-directory (expand-file-name "media" user-home-directory)) |
|
60 | ||
41 | 61 | (defvar default-theme 'leuven-dark) |
62 | (defvar company-source-directory (join-paths user-lab-directory "comp")) |
|
63 | (defvar company-domain "compiler.company") |
|
64 | (defvar company-name "The Compiler Company, LLC") |
|
65 | (defvar company-vc-domain "vc.compiler.company") |
|
66 | (defvar company-home "the.compiler.company") |
|
67 | ||
30 | 68 | ;;; Theme |
34 | 69 | (defun load-default-theme () (interactive) (load-theme default-theme)) |
70 | ||
71 | (add-hook 'after-init-hook #'load-default-theme) |
|
27 | 72 | |
73 | ;;; Packages |
|
74 | (package-initialize) |
|
28 | 75 | |
27 | 76 | (with-eval-after-load 'package |
34 | 77 | (setq package-archives |
78 | '(("gnu" . "https://elpa.gnu.org/packages/") |
|
79 | ("nongnu" . "https://elpa.nongnu.org/nongnu/") |
|
80 | ("melpa" . "https://melpa.org/packages/")) |
|
81 | use-package-always-ensure t |
|
82 | use-package-expand-minimally t) |
|
28 | 83 | (add-packages |
187
a962648ad6d5
add dir-locals and eglot-x
Richard Westhaver <ellis@rwest.io>
parents:
182
diff
changeset
|
84 | eglot-x ;; LSP extensions |
33 | 85 | org-web-tools ;; web parsing |
86 | citeproc ;; citations |
|
87 | all-the-icons all-the-icons-dired all-the-icons-ibuffer ;; icons |
|
44 | 88 | corfu orderless cape ;; completion |
33 | 89 | slime ;; common lisp server |
149 | 90 | bbdb |
91 | slime-company |
|
33 | 92 | which-key ;; key helper |
93 | ;; langs |
|
94 | rust-mode) |
|
28 | 95 | (package-install-selected-packages t)) |
26 | 96 | |
45 | 97 | ;;; Env |
62 | 98 | (require 'exec-path-from-shell) |
99 | (exec-path-from-shell-copy-env "SSH_AGENT_PID") |
|
100 | (exec-path-from-shell-copy-env "SSH_AUTH_SOCK") |
|
101 | (exec-path-from-shell-copy-env "PATH") |
|
45 | 102 | (add-to-list 'exec-path (expand-file-name "~/.cargo/bin/")) |
103 | (add-to-list 'exec-path (expand-file-name "~/.local/bin/")) |
|
104 | (add-to-list 'exec-path "/bin/") |
|
105 | (add-to-list 'exec-path "/usr/local/sbin/") |
|
106 | ||
33 | 107 | ;;; Completions |
108 | (use-package corfu |
|
44 | 109 | :init (global-corfu-mode)) |
110 | ||
111 | (use-package cape |
|
112 | ;; Bind dedicated completion commands |
|
113 | ;; Alternative prefix keys: C-c p, M-p, M-+, ... |
|
114 | :bind (("C-c p p" . completion-at-point) ;; capf |
|
115 | ("C-c p t" . complete-tag) ;; etags |
|
116 | ("C-c p d" . cape-dabbrev) ;; or dabbrev-completion |
|
117 | ("C-c p h" . cape-history) |
|
118 | ("C-c p f" . cape-file) |
|
119 | ("C-c p k" . cape-keyword) |
|
120 | ("C-c p s" . cape-elisp-symbol) |
|
121 | ("C-c p e" . cape-elisp-block) |
|
122 | ("C-c p a" . cape-abbrev) |
|
123 | ("C-c p l" . cape-line) |
|
124 | ("C-c p w" . cape-dict) |
|
125 | ("C-c p :" . cape-emoji) |
|
126 | ("C-c p \\" . cape-tex) |
|
127 | ("C-c p _" . cape-tex) |
|
128 | ("C-c p ^" . cape-tex) |
|
129 | ("C-c p &" . cape-sgml) |
|
130 | ("C-c p r" . cape-rfc1345)) |
|
131 | :init |
|
132 | ;; Add to the global default value of `completion-at-point-functions' which is |
|
133 | ;; used by `completion-at-point'. The order of the functions matters, the |
|
134 | ;; first function returning a result wins. Note that the list of buffer-local |
|
135 | ;; completion functions takes precedence over the global list. |
|
148
0d9d5cd46af5
added net/stream.rs, change def-ts-lang to macrolet form
ellis <ellis@rwest.io>
parents:
126
diff
changeset
|
136 | (add-to-list 'completion-at-point-functions #'cape-dabbrev) |
0d9d5cd46af5
added net/stream.rs, change def-ts-lang to macrolet form
ellis <ellis@rwest.io>
parents:
126
diff
changeset
|
137 | (add-to-list 'completion-at-point-functions #'cape-abbrev) |
59 | 138 | ;; (add-to-list 'completion-at-point-functions #'cape-history) |
60 | 139 | ;; (add-to-list 'completion-at-point-functions #'cape-keyword) |
148
0d9d5cd46af5
added net/stream.rs, change def-ts-lang to macrolet form
ellis <ellis@rwest.io>
parents:
126
diff
changeset
|
140 | (add-to-list 'completion-at-point-functions #'cape-file) |
59 | 141 | ;; (add-to-list 'completion-at-point-functions #'cape-line) |
142 | ;; (add-to-list 'completion-at-point-functions #'cape-elisp-block) |
|
60 | 143 | ;; (add-to-list 'completion-at-point-functions #'cape-tex) |
59 | 144 | ;; (add-to-list 'completion-at-point-functions #'cape-sgml) |
145 | ;; (add-to-list 'completion-at-point-functions #'cape-rfc1345) |
|
146 | ;; (add-to-list 'completion-at-point-functions #'cape-dict) |
|
147 | ;; (add-to-list 'completion-at-point-functions #'cape-elisp-symbol) |
|
148 | ;; (add-to-list 'completion-at-point-functions #'cape-emoji) |
|
149 | ) |
|
33 | 150 | |
151 | (use-package orderless |
|
34 | 152 | :custom |
33 | 153 | (completion-styles '(orderless basic)) |
154 | (completion-category-overrides '((file (styles basic partial-completion))))) |
|
155 | ||
30 | 156 | ;;; Desktop |
34 | 157 | (setopt desktop-dirname (expand-file-name "sessions" user-emacs-directory)) |
33 | 158 | |
30 | 159 | ;;; Multisession |
160 | (setq multisession-storage 'sqlite) |
|
161 | ||
148
0d9d5cd46af5
added net/stream.rs, change def-ts-lang to macrolet form
ellis <ellis@rwest.io>
parents:
126
diff
changeset
|
162 | ;;; Kill Ring |
0d9d5cd46af5
added net/stream.rs, change def-ts-lang to macrolet form
ellis <ellis@rwest.io>
parents:
126
diff
changeset
|
163 | (kill-ring-deindent-mode) |
0d9d5cd46af5
added net/stream.rs, change def-ts-lang to macrolet form
ellis <ellis@rwest.io>
parents:
126
diff
changeset
|
164 | |
21 | 165 | ;;; VC |
166 | ;; use rhg, fallback to hg. see hgrc |
|
167 | (if (file-exists-p "~/.local/bin/rhg") |
|
34 | 168 | (setq hg-binary "~/.local/bin/rhg")) |
21 | 169 | |
170 | ;;; Dired |
|
29 | 171 | (add-hook 'dired-mode-hook #'all-the-icons-dired-mode) |
172 | (add-hook 'ibuffer-mode-hook #'all-the-icons-ibuffer-mode) |
|
26 | 173 | |
21 | 174 | ;;; Lisp |
26 | 175 | (use-package lisp-mode |
176 | :ensure nil |
|
33 | 177 | :custom |
126 | 178 | inferior-lisp-program "sbcl --dynamic-space-size=8G" |
33 | 179 | scheme-program-name "gsi" |
180 | guile-program "guile" |
|
181 | cmulisp-program "lisp" |
|
182 | scsh-program "scsh") |
|
26 | 183 | |
184 | (use-package slime |
|
44 | 185 | :ensure t |
26 | 186 | :config |
44 | 187 | (setq slime-contribs '(slime-fancy slime-quicklisp)) |
53 | 188 | |
189 | (put 'make-instance 'common-lisp-indent-function 1) |
|
190 | (put 'reinitialize-instance 'common-lisp-indent-function 1) |
|
191 | ||
26 | 192 | (defvar slime-toggle nil) |
193 | (defun slime-toggle () |
|
194 | "toggle between lisp file and slime-repl" |
|
195 | (interactive) |
|
196 | (if (eq major-mode 'slime-repl-mode) |
|
126 | 197 | (setq slime-toggle (pop-to-buffer (or slime-toggle (read-buffer "lisp file: ")))) |
21 | 198 | (progn |
44 | 199 | (setq slime-toggle (current-buffer)) |
53 | 200 | (slime-repl)))) |
201 | ||
202 | (defun clouseau-inspect (string) |
|
203 | "Inspect a lisp value with Clouseau. make sure to load clouseau |
|
204 | with a custom core or in your init file before using this |
|
205 | function: '(ql:quickload :clouseau)'." |
|
206 | (interactive |
|
207 | (list (slime-read-from-minibuffer |
|
208 | "Inspect value (evaluated): " |
|
209 | (slime-sexp-at-point)))) |
|
210 | (let ((inspector 'cl-user::*clouseau-inspector*)) |
|
211 | (slime-eval-async |
|
212 | `(cl:progn |
|
213 | (cl:defvar ,inspector nil) |
|
214 | ;; (Re)start the inspector if necessary. |
|
215 | (cl:unless (cl:and (clim:application-frame-p ,inspector) |
|
216 | (clim-internals::frame-process ,inspector)) |
|
217 | (cl:setf ,inspector (cl:nth-value 1 (clouseau:inspect nil :new-process t)))) |
|
218 | ;; Tell the inspector to visualize the correct datum. |
|
219 | (cl:setf (clouseau:root-object ,inspector :run-hook-p t) |
|
220 | (cl:eval (cl:read-from-string ,string))) |
|
221 | ;; Return nothing. |
|
222 | (cl:values))))) |
|
223 | ||
182 | 224 | (define-key slime-prefix-map (kbd "i") 'clouseau-inspect) |
225 | (setq slime-threads-update-interval 1)) |
|
21 | 226 | |
187
a962648ad6d5
add dir-locals and eglot-x
Richard Westhaver <ellis@rwest.io>
parents:
182
diff
changeset
|
227 | ;;; Eglot |
a962648ad6d5
add dir-locals and eglot-x
Richard Westhaver <ellis@rwest.io>
parents:
182
diff
changeset
|
228 | (with-eval-after-load 'eglot |
a962648ad6d5
add dir-locals and eglot-x
Richard Westhaver <ellis@rwest.io>
parents:
182
diff
changeset
|
229 | (unless (package-installed-p 'eglot-x) |
a962648ad6d5
add dir-locals and eglot-x
Richard Westhaver <ellis@rwest.io>
parents:
182
diff
changeset
|
230 | (package-vc-install '(eglot-x :url "https://vc.compiler.company/packy/eglot-x.git"))) |
a962648ad6d5
add dir-locals and eglot-x
Richard Westhaver <ellis@rwest.io>
parents:
182
diff
changeset
|
231 | (require 'eglot-x) |
a962648ad6d5
add dir-locals and eglot-x
Richard Westhaver <ellis@rwest.io>
parents:
182
diff
changeset
|
232 | (add-to-list 'eglot-server-programs |
a962648ad6d5
add dir-locals and eglot-x
Richard Westhaver <ellis@rwest.io>
parents:
182
diff
changeset
|
233 | '((rust-ts-mode rust-mode) . |
a962648ad6d5
add dir-locals and eglot-x
Richard Westhaver <ellis@rwest.io>
parents:
182
diff
changeset
|
234 | ("rust-analyzer" :initializationOptions (:check (:command "clippy"))))) |
a962648ad6d5
add dir-locals and eglot-x
Richard Westhaver <ellis@rwest.io>
parents:
182
diff
changeset
|
235 | (eglot-x-setup)) |
a962648ad6d5
add dir-locals and eglot-x
Richard Westhaver <ellis@rwest.io>
parents:
182
diff
changeset
|
236 | |
21 | 237 | ;;; Rust |
238 | (add-hook 'rust-mode-hook 'eglot-ensure) |
|
187
a962648ad6d5
add dir-locals and eglot-x
Richard Westhaver <ellis@rwest.io>
parents:
182
diff
changeset
|
239 | |
30 | 240 | (setq rust-rustfmt-switches nil |
241 | rust-indent-offset 2) |
|
242 | ||
243 | ;;; Python |
|
244 | (setq python-indent-offset 2) |
|
245 | (add-hook 'python-mode-hook 'eglot-ensure) |
|
246 | ||
247 | ;;; Bash |
|
248 | (setq sh-basic-offset 2) |
|
249 | ||
31 | 250 | ;;; Comments |
251 | (defcustom prog-comment-keywords |
|
252 | '("TODO" "REVIEW" "FIX" "HACK" "RESEARCH") |
|
253 | "List of strings with comment keywords." |
|
254 | :group 'default) |
|
255 | ||
256 | (defcustom prog-comment-timestamp-format-concise "%F" |
|
257 | "Specifier for date in `prog-comment-timestamp-keyword'. |
|
258 | Refer to the doc string of `format-time-string' for the available |
|
259 | options." |
|
260 | :group 'default) |
|
261 | ||
262 | (defcustom prog-comment-timestamp-format-verbose "%F %T %z" |
|
263 | "Like `prog-comment-timestamp-format-concise', but longer." |
|
264 | :group 'default) |
|
265 | ||
266 | ;;;###autoload |
|
267 | (defun prog-comment-dwim (arg) |
|
268 | "Flexible, do-what-I-mean commenting. |
|
269 | ||
270 | If region is active and ARG is either a numeric argument greater |
|
271 | than one or a universal prefix (\\[universal-argument]), then |
|
272 | apply `comment-kill' on all comments in the region. |
|
273 | ||
274 | If the region is active and no ARG is supplied, or is equal to a |
|
275 | numeric prefix of 1, then toggle the comment status of the region. |
|
276 | ||
277 | Else toggle the comment status of the line at point. With a |
|
278 | numeric prefix ARG, do so for ARGth lines (negative prefix |
|
279 | operates on the lines before point)." |
|
280 | (interactive "p") |
|
281 | (cond |
|
282 | ((and (> arg 1) (use-region-p)) |
|
283 | (let* ((beg (region-beginning)) |
|
284 | (end (region-end)) |
|
285 | (num (count-lines beg end))) |
|
286 | (save-excursion |
|
287 | (goto-char beg) |
|
288 | (comment-kill num)))) |
|
289 | ((use-region-p) |
|
290 | (comment-or-uncomment-region (region-beginning) (region-end))) |
|
291 | (t |
|
292 | (save-excursion (comment-line (or arg 1)))))) |
|
293 | ||
294 | (defvar prog-comment--keyword-hist '() |
|
295 | "Input history of selected comment keywords.") |
|
296 | ||
297 | (defun prog-comment--keyword-prompt (keywords) |
|
298 | "Prompt for candidate among KEYWORDS." |
|
299 | (let ((def (car prog-comment--keyword-hist))) |
|
300 | (completing-read |
|
301 | (format "Select keyword [%s]: " def) |
|
302 | keywords nil nil nil 'prog-comment--keyword-hist def))) |
|
303 | ||
304 | ||
305 | ;;;###autoload |
|
306 | (defun prog-comment-timestamp-keyword (keyword &optional verbose) |
|
307 | "Add timestamped comment with KEYWORD. |
|
308 | ||
309 | When called interactively, the list of possible keywords is that |
|
310 | of `prog-comment-keywords', though it is possible to |
|
311 | input arbitrary text. |
|
312 | ||
313 | If point is at the beginning of the line or if line is empty (no |
|
314 | characters at all or just indentation), the comment is started |
|
315 | there in accordance with `comment-style'. Any existing text |
|
316 | after the point will be pushed to a new line and will not be |
|
317 | turned into a comment. |
|
318 | ||
319 | If point is anywhere else on the line, the comment is indented |
|
320 | with `comment-indent'. |
|
321 | ||
322 | The comment is always formatted as 'DELIMITER KEYWORD DATE:', |
|
323 | with the date format being controlled by the variable |
|
324 | `prog-comment-timestamp-format-concise'. |
|
325 | ||
326 | With optional VERBOSE argument (such as a prefix argument |
|
327 | `\\[universal-argument]'), use an alternative date format, as |
|
328 | specified by `prog-comment-timestamp-format-verbose'." |
|
329 | (interactive |
|
330 | (list |
|
331 | (prog-comment--keyword-prompt prog-comment-keywords) |
|
332 | current-prefix-arg)) |
|
333 | (let* ((date (if verbose |
|
334 | comment-timestamp-format-verbose |
|
34 | 335 | prog-comment-timestamp-format-concise)) |
336 | (string (format "%s %s: " keyword (format-time-string date))) |
|
31 | 337 | (beg (point))) |
338 | (cond |
|
339 | ((or (eq beg (point-at-bol)) |
|
340 | (default-line-regexp-p 'empty)) |
|
341 | (let* ((maybe-newline (unless (default-line-regexp-p 'empty 1) "\n"))) |
|
342 | ;; NOTE 2021-07-24: we use this `insert' instead of |
|
343 | ;; `comment-region' because of a yet-to-be-determined bug that |
|
344 | ;; traps `undo' to the two states between the insertion of the |
|
345 | ;; string and its transformation into a comment. |
|
346 | (insert |
|
347 | (concat comment-start |
|
348 | ;; NOTE 2021-07-24: See function `comment-add' for |
|
349 | ;; why we need this. |
|
350 | (make-string |
|
351 | (comment-add nil) |
|
352 | (string-to-char comment-start)) |
|
353 | comment-padding |
|
354 | string |
|
355 | comment-end)) |
|
356 | (indent-region beg (point)) |
|
357 | (when maybe-newline |
|
358 | (save-excursion (insert maybe-newline))))) |
|
359 | (t |
|
360 | (comment-indent t) |
|
361 | (insert (concat " " string)))))) |
|
362 | ||
34 | 363 | (setq hexl-bits 8) |
31 | 364 | (setq tab-width 4) |
365 | ||
21 | 366 | ;;; Keyboard Macros |
367 | (defun toggle-macro-recording () |
|
368 | (interactive) |
|
369 | (if defining-kbd-macro |
|
370 | (end-kbd-macro) |
|
371 | (start-kbd-macro nil))) |
|
372 | ||
373 | (defun play-macro-if-not-playing () |
|
374 | (interactive) |
|
375 | (if defining-kbd-macro |
|
376 | (end-kbd-macro) |
|
377 | (call-last-kbd-macro))) |
|
30 | 378 | |
379 | ;;; Registers |
|
380 | ;; - additional register vtypes: buffer |
|
381 | (defun decrement-register (number register) |
|
382 | "Subtract NUMBER from the contents of register REGISTER. |
|
383 | Interactively, NUMBER is the prefix arg." |
|
384 | (interactive "p\ncDecrement register: ") |
|
385 | (increment-register (- number) register)) |
|
386 | ||
387 | (defun copy-register (a b) |
|
388 | "Copy register A to B." |
|
389 | (interactive |
|
390 | (list (register-read-with-preview "From register: ") |
|
34 | 391 | (register-read-with-preview "To register: "))) |
30 | 392 | (set-register b (get-register a))) |
393 | ||
394 | (defun buffer-to-register (register &optional delete) |
|
395 | "Put current buffer in register - this would also work for |
|
396 | just buffers, as switch-to-buffer can use both, but it |
|
397 | facilitates for easier saving/restoring of registers." |
|
398 | (interactive "cPut current buffername in register: \nP.") |
|
399 | (set-register register (cons 'buffer (buffer-name (current-buffer))))) |
|
34 | 400 | |
30 | 401 | (defun file-to-register (register &optional delete) |
402 | "This is better than put-buffer-in-register for file-buffers, because a closed |
|
403 | file can be opened again, but does not work for no-file-buffers." |
|
404 | (interactive "cPut the filename of current buffer in register: \nP") |
|
405 | (set-register register (cons 'file (buffer-file-name (current-buffer))))) |
|
34 | 406 | |
30 | 407 | (defun file-query-to-register (register &optional delete) |
34 | 408 | (interactive |
409 | (list |
|
30 | 410 | (register-read-with-preview "File query to register: "))) |
411 | (set-register register (list 'file-query (buffer-file-name (current-buffer)) (point)))) |
|
412 | ||
413 | ;; additional register-val handlers |
|
414 | ;; (cl-defmethod register-val-jump-to :around ((val cons) delete) |
|
415 | ;; (cond |
|
416 | ;; (t (cl-call-next-method val delete)))) |
|
417 | ||
21 | 418 | ;;; Outlines |
34 | 419 | (defun outline-hook (&optional rx) |
21 | 420 | "Enable `outline-minor-mode' and set `outline-regexp'." |
57 | 421 | (when rx (setq-local outline-regexp rx)) |
422 | (outline-minor-mode 1)) |
|
21 | 423 | |
57 | 424 | (setq outline-minor-mode-use-buttons nil) |
34 | 425 | |
426 | (defun add-outline-hook (mode &optional rx) |
|
427 | (let ((sym (symb mode "-hook"))) |
|
428 | (add-hook sym (lambda () (outline-hook rx))))) |
|
21 | 429 | |
430 | (defmacro outline-hooks (&rest pairs) |
|
431 | `(mapc (lambda (x) (add-outline-hook (car x) (cadr x))) ',pairs)) |
|
432 | ||
433 | (outline-hooks (asm-mode ";;;+") |
|
34 | 434 | (nasm-mode ";;;+") |
435 | (rust-mode "\\(//!\\|////+\\)") |
|
436 | (sh-mode "###+") |
|
437 | (sh-script-mode "###+") |
|
438 | (makefile-mode "###+") |
|
57 | 439 | (conf-mode "###+") |
440 | (common-lisp-mode) |
|
441 | (emacs-lisp-mode) |
|
442 | (lisp-data-mode) |
|
443 | (org-mode) |
|
444 | (css-mode) |
|
445 | (html-mode) |
|
446 | (skel-mode)) |
|
30 | 447 | |
21 | 448 | ;;; Scratch |
449 | (defcustom default-scratch-buffer-mode 'lisp-interaction-mode |
|
34 | 450 | "Default major mode for new scratch buffers" |
451 | :group 'default) |
|
21 | 452 | |
30 | 453 | ;; Adapted from the `scratch.el' package by Ian Eure. |
454 | (defun default-scratch-list-modes () |
|
455 | "List known major modes." |
|
456 | (cl-loop for sym the symbols of obarray |
|
457 | for name = (symbol-name sym) |
|
458 | when (and (functionp sym) |
|
459 | (not (member sym minor-mode-list)) |
|
460 | (string-match "-mode$" name) |
|
461 | (not (string-match "--" name))) |
|
462 | collect name)) |
|
463 | ||
464 | (defun default-scratch-buffer-setup (region &optional mode) |
|
465 | "Add contents to `scratch' buffer and name it accordingly. |
|
466 | ||
467 | REGION is added to the contents to the new buffer. |
|
468 | ||
469 | Use the current buffer's major mode by default. With optional |
|
470 | MODE use that major mode instead." |
|
471 | (let* ((major (or mode major-mode)) |
|
472 | (string (format "Scratch buffer for: %s\n\n" major)) |
|
473 | (text (concat string region)) |
|
474 | (buf (format "*Scratch for %s*" major))) |
|
475 | (with-current-buffer (get-buffer-create buf) |
|
476 | (funcall major) |
|
34 | 477 | (save-excursion |
30 | 478 | (insert text) |
479 | (goto-char (point-min)) |
|
480 | (comment-region (point-at-bol) (point-at-eol))) |
|
34 | 481 | (vertical-motion 2)) |
30 | 482 | (pop-to-buffer buf))) |
483 | ||
484 | ;;;###autoload |
|
485 | (defun default-scratch-buffer (&optional arg) |
|
486 | "Produce a bespoke scratch buffer matching current major mode. |
|
487 | ||
488 | With optional ARG as a prefix argument (\\[universal-argument]), |
|
489 | use `default-scratch-buffer-mode'. |
|
490 | ||
491 | With ARG as a double prefix argument, prompt for a major mode |
|
492 | with completion. |
|
493 | ||
494 | If region is active, copy its contents to the new scratch |
|
495 | buffer." |
|
496 | (interactive "P") |
|
497 | (let* ((default-mode default-scratch-buffer-mode) |
|
498 | (modes (default-scratch-list-modes)) |
|
499 | (region (with-current-buffer (current-buffer) |
|
500 | (if (region-active-p) |
|
501 | (buffer-substring-no-properties |
|
502 | (region-beginning) |
|
503 | (region-end)) |
|
504 | ""))) |
|
505 | (m)) |
|
506 | (pcase (prefix-numeric-value arg) |
|
507 | (16 (progn |
|
508 | (setq m (intern (completing-read "Select major mode: " modes nil t))) |
|
509 | (default-scratch-buffer-setup region m))) |
|
510 | (4 (default-scratch-buffer-setup region default-mode)) |
|
511 | (_ (default-scratch-buffer-setup region))))) |
|
512 | ||
513 | ;;;###autoload |
|
514 | (defun scratch-new () |
|
515 | "create a new scratch buffer. (could be *scratch* - *scratchN*)" |
|
516 | (interactive) |
|
517 | (let ((n 0) |
|
518 | bufname) |
|
519 | (while (progn |
|
520 | (setq bufname |
|
34 | 521 | (concat "*scratch" |
30 | 522 | (if (= n 0) "" (int-to-string n)) |
523 | "*")) |
|
524 | (setq n (1+ n)) |
|
525 | (get-buffer bufname))) |
|
526 | (switch-to-buffer (get-buffer-create bufname)) |
|
527 | (insert initial-scratch-message) |
|
528 | (lisp-interaction-mode))) |
|
529 | ||
21 | 530 | ;;; Shell |
531 | (defun set-no-process-query-on-exit () |
|
532 | (let ((proc (get-buffer-process (current-buffer)))) |
|
533 | (when (processp proc) |
|
534 | (set-process-query-on-exit-flag proc nil)))) |
|
535 | ||
536 | (add-hook 'shell-mode-hook 'set-no-process-query-on-exit) |
|
537 | (add-hook 'term-exec-hook 'set-no-process-query-on-exit) |
|
30 | 538 | |
21 | 539 | ;;; Eshell |
540 | (defun eshell-new() |
|
541 | "Open a new instance of eshell." |
|
542 | (interactive) |
|
543 | (eshell 'Z)) |
|
544 | ||
30 | 545 | (setq eshell-highlight-prompt t |
21 | 546 | eshell-hist-ignoredups t |
547 | eshell-save-history-on-exit t |
|
548 | eshell-prefer-lisp-functions nil |
|
549 | eshell-destroy-buffer-when-process-dies t) |
|
550 | ||
551 | (add-hook 'eshell-mode-hook |
|
34 | 552 | (lambda () |
553 | (eshell/alias "d" "dired $1") |
|
554 | (eshell/alias "ff" "find-file $1") |
|
41 | 555 | (eshell/alias "hgfe" "hg-fast-export.sh"))) |
21 | 556 | |
557 | (defun eshell/clear () |
|
558 | "Clear the eshell buffer." |
|
559 | (let ((inhibit-read-only t)) |
|
560 | (erase-buffer) |
|
561 | (eshell-send-input))) |
|
562 | ||
563 | (defun eshell-quit-or-delete-char (arg) |
|
34 | 564 | (interactive "p") |
565 | (if (and (eolp) (looking-back eshell-prompt-regexp)) |
|
566 | (progn |
|
567 | (eshell-life-is-too-much) ; Why not? (eshell/exit) |
|
568 | (ignore-errors |
|
569 | (delete-window))) |
|
570 | (delete-forward-char arg))) |
|
21 | 571 | |
572 | (add-hook 'eshell-mode-hook |
|
573 | (lambda () |
|
574 | (bind-keys :map eshell-mode-map |
|
575 | ("C-d" . eshell-quit-or-delete-char)))) |
|
576 | ||
577 | (defun eshell-next-prompt (n) |
|
578 | "Move to end of Nth next prompt in the buffer. See `eshell-prompt-regexp'." |
|
579 | (interactive "p") |
|
580 | (re-search-forward eshell-prompt-regexp nil t n) |
|
581 | (when eshell-highlight-prompt |
|
582 | (while (not (get-text-property (line-beginning-position) 'read-only) ) |
|
583 | (re-search-forward eshell-prompt-regexp nil t n))) |
|
584 | (eshell-skip-prompt)) |
|
585 | ||
586 | (defun eshell-previous-prompt (n) |
|
587 | "Move to end of Nth previous prompt in the buffer. See `eshell-prompt-regexp'." |
|
588 | (interactive "p") |
|
589 | (backward-char) |
|
590 | (eshell-next-prompt (- n))) |
|
591 | ||
592 | (defun eshell-insert-history () |
|
593 | "Displays the eshell history to select and insert back into your eshell." |
|
594 | (interactive) |
|
595 | (insert (ido-completing-read "Eshell history: " |
|
596 | (delete-dups |
|
597 | (ring-elements eshell-history-ring))))) |
|
34 | 598 | ;;; Tramp |
599 | ||
600 | (setopt tramp-default-method "ssh" |
|
601 | tramp-default-user user-login-name |
|
602 | tramp-default-host "localhost") |
|
21 | 603 | ;;; Org |
604 | ;; todos |
|
605 | (setq org-todo-keywords |
|
606 | '((type "TBD(0!)" "TODO(t!)" "|") |
|
93 | 607 | (type "WIP(w!)" "|") |
608 | (sequence "FIND(q!)" "READ(r@!)" "WATCH(W@!)" "|") |
|
609 | (sequence "RESEARCH(s!)" "RECORD(e!)" "|") |
|
610 | (sequence "OUTLINE(O!)" "RESEARCH(A!)" "DRAFT(M!)" "REVIEW(R!)" "|") |
|
611 | (sequence "FIX(i!)" "TEST(t!)" "|") |
|
612 | (type "GOTO(g!)" "HACK(h!)" "NOTE(n!)" "CODE(c!)" "LINK(l!)" "|") |
|
613 | (type "KLUDGE(k@!)" "|") |
|
614 | (sequence "|" "DONE(d!)" "NOPE(x@!)" "FOUND(f@!)"))) |
|
21 | 615 | ;; captures |
616 | (setq org-capture-templates |
|
617 | '(("t" "task" entry (file "inbox.org") "* %^{title}\n- %?" :prepend t) |
|
34 | 618 | ("1" "current-task-item" item (clock) "%i%?") |
619 | ("2" "current-task-checkbox" checkitem (clock) "%i%?") |
|
620 | ("3" "current-task-region" plain (clock) "%i" :immediate-finish t :empty-lines 1) |
|
621 | ("4" "current-task-kill" plain (clock) "%c" :immediate-finish t :empty-lines 1) |
|
622 | ("l" "log" item (file+headline "log.org" "log") "%U %?" :prepend t) |
|
623 | ("s" "secret" table-line (file+function "krypt" org-ask-location) "| %^{key} | %^{val} |" :immediate-finish t :kill-buffer t) |
|
624 | ("n" "note" plain (file+function "notes.org" org-ask-location) "%?") |
|
625 | ("i" "idea" entry (file "inbox.org") "* OUTLINE %?\n:notes:\n:end:\n- _outline_ [/]\n - [ ] \n - [ ] \n- _refs_" :prepend t) |
|
626 | ("b" "bug" entry (file "inbox.org") "* FIX %?\n- _review_\n- _fix_\n- _test_" :prepend t) |
|
627 | ("r" "research" entry (file "inbox.org") "* RESEARCH %?\n:notes:\n:end:\n- _refs_" :prepend t))) |
|
21 | 628 | (setq org-html-htmlize-output-type 'css |
41 | 629 | org-html-head-include-default-style nil |
630 | ;; comp2 default |
|
631 | org-ascii-text-width 80) |
|
21 | 632 | |
633 | (org-crypt-use-before-save-magic) |
|
634 | ||
635 | (setq org-structure-template-alist |
|
636 | '(("s" . "src") |
|
34 | 637 | ("e" . "src emacs-lisp") |
638 | ("x" . "src shell") |
|
639 | ("l" . "src lisp") |
|
640 | ("h" . "export html") |
|
641 | ("p" . "src python") |
|
642 | ("r" . "src rust") |
|
643 | ("E" . "example") |
|
644 | ("q" . "quote") |
|
645 | ("c" . "center") |
|
646 | ("C" . "comment") |
|
647 | ("v" . "verse"))) |
|
21 | 648 | |
96 | 649 | (setopt org-preview-latex-image-directory "~/.emacs.d/.cache/ltximg" |
650 | org-latex-image-default-width "8cm" |
|
651 | org-refile-use-cache t |
|
652 | org-refile-allow-creating-parent-nodes 'confirm |
|
21 | 653 | |
96 | 654 | org-refile-targets '((nil :maxlevel . 3) |
655 | (org-agenda-files :maxlevel . 3)) |
|
656 | org-confirm-babel-evaluate nil |
|
657 | org-src-fontify-natively t |
|
658 | org-src-tabs-act-natively t |
|
659 | org-footnote-section nil |
|
660 | org-log-into-drawer t |
|
661 | org-log-states-order-reversed nil |
|
662 | org-clock-persist 'history) |
|
21 | 663 | |
96 | 664 | (add-hook 'after-init-hook #'org-clock-persistence-insinuate) |
21 | 665 | |
666 | (defun org-todo-at-date (date) |
|
667 | "create a todo entry for a given date." |
|
668 | (interactive (list (org-time-string-to-time (org-read-date)))) |
|
669 | (cl-flet ((org-current-effective-time (&rest r) date) |
|
670 | (org-today (&rest r) (time-to-days date))) |
|
671 | (cond ((eq major-mode 'org-mode) (org-todo)) |
|
672 | ((eq major-mode 'org-agenda-mode) (org-agenda-todo))))) |
|
673 | ||
674 | (defun org-ask-location () |
|
675 | "prompt for a location\"\"" |
|
676 | (let* ((org-refile-targets '((nil :maxlevel . 9))) |
|
677 | (hd (condition-case nil |
|
678 | (car (org-refile-get-location)) |
|
679 | (error (car org-refile-history))))) |
|
680 | (goto-char (point-min)) |
|
681 | (outline-next-heading) |
|
682 | (if (re-search-forward |
|
683 | (format org-complex-heading-regexp-format (regexp-quote hd)) |
|
684 | nil t) |
|
685 | (goto-char (point-at-bol)) |
|
686 | (goto-char (point-max)) |
|
687 | (or (bolp) (insert "\n")) |
|
688 | (insert "* " hd "\n"))) |
|
689 | (end-of-line)) |
|
690 | ||
691 | (defun org-capture-fileref-snippet (f type headers func-name) |
|
692 | (let* ((code-snippet |
|
693 | (buffer-substring-no-properties (mark) (- (point) 1))) |
|
694 | (file-name (buffer-file-name)) |
|
695 | (file-base (file-name-nondirectory file-name)) |
|
696 | (line-number (line-number-at-pos (region-beginning))) |
|
697 | (initial-txt (if (null func-name) |
|
698 | (format "From [[file:%s::%s][%s]]:" |
|
699 | file-name line-number file-base) |
|
700 | (format "From ~%s~ (in [[file:%s::%s][%s]]):" |
|
701 | func-name file-name line-number |
|
702 | file-base)))) |
|
703 | (format " |
|
704 | %s |
|
705 | #+BEGIN_%s %s |
|
706 | %s |
|
707 | #+END_%s" initial-txt type headers code-snippet type))) |
|
708 | ||
709 | (defun org-capture-clip-snippet (f) |
|
710 | "Given a file, F, this captures the currently selected text |
|
711 | within an Org EXAMPLE block and a backlink to the file." |
|
712 | (with-current-buffer (find-buffer-visiting f) |
|
713 | (org-capture-fileref-snippet f "EXAMPLE" "" nil))) |
|
714 | ||
715 | (defun org-capture-code-snippet (f) |
|
716 | "Given a file, F, this captures the currently selected text |
|
717 | within an Org SRC block with a language based on the current mode |
|
718 | and a backlink to the function and the file." |
|
719 | (with-current-buffer (find-buffer-visiting f) |
|
720 | (let ((org-src-mode (replace-regexp-in-string "-mode" "" (format "%s" major-mode))) |
|
721 | (func-name (which-function))) |
|
722 | (org-capture-fileref-snippet f "SRC" org-src-mode func-name)))) |
|
723 | ||
724 | (defun region-to-clocked-task (start end) |
|
725 | "Copies the selected text to the currently clocked in org-mode task." |
|
726 | (interactive "r") |
|
727 | (org-capture-string (buffer-substring-no-properties start end) "3")) |
|
728 | ||
729 | (setq org-global-properties |
|
730 | '(quote (("EFFORT_ALL" . "0:15 0:30 0:45 1:00 2:00 3:00 4:00 5:00 6:00 0:00") |
|
731 | ("STYLE_ALL" . "habit")))) |
|
732 | ||
733 | (defun org-mode-ask-effort () |
|
734 | "Ask for an effort estimate when clocking in." |
|
735 | (unless (org-entry-get (point) "Effort") |
|
736 | (let ((effort |
|
737 | (completing-read |
|
738 | "Effort: " |
|
739 | (org-entry-get-multivalued-property (point) "Effort")))) |
|
740 | (unless (equal effort "") |
|
741 | (org-set-property "Effort" effort))))) |
|
742 | ||
743 | (add-hook 'org-clock-in-prepare-hook |
|
744 | 'org-mode-ask-effort) |
|
745 | ||
746 | ;;;###autoload |
|
747 | (defun org-adjust-tags-column-reset-tags () |
|
748 | "In org-mode buffers it will reset tag position according to |
|
749 | `org-tags-column'." |
|
750 | (when (and |
|
751 | (not (string= (buffer-name) "*Remember*")) |
|
752 | (eql major-mode 'org-mode)) |
|
753 | (let ((b-m-p (buffer-modified-p))) |
|
754 | (condition-case nil |
|
755 | (save-excursion |
|
756 | (goto-char (point-min)) |
|
757 | (command-execute 'outline-next-visible-heading) |
|
758 | ;; disable (message) that org-set-tags generates |
|
759 | (flet ((message (&rest ignored) nil)) |
|
34 | 760 | (org-set-tags 1 t)) |
21 | 761 | (set-buffer-modified-p b-m-p)) |
762 | (error nil))))) |
|
763 | ||
764 | ;;;###autoload |
|
765 | (defun org-align-all-tables () |
|
766 | "align all tables in current buffer" |
|
767 | (interactive) |
|
768 | (org-table-map-tables 'org-table-align 'quietly)) |
|
769 | ||
770 | (defun org-remove-redundant-tags () |
|
771 | "Remove redundant tags of headlines in current buffer. |
|
772 | ||
773 | A tag is considered redundant if it is local to a headline and |
|
774 | inherited by a parent headline." |
|
775 | (interactive) |
|
776 | (when (eq major-mode 'org-mode) |
|
777 | (save-excursion |
|
778 | (org-map-entries |
|
779 | (lambda () |
|
780 | (let ((alltags (split-string (or (org-entry-get (point) "ALLTAGS") "") ":")) |
|
781 | local inherited tag) |
|
782 | (dolist (tag alltags) |
|
783 | (if (get-text-property 0 'inherited tag) |
|
784 | (push tag inherited) (push tag local))) |
|
785 | (dolist (tag local) |
|
786 | (if (member tag inherited) (org-toggle-tag tag 'off))))) |
|
787 | t nil)))) |
|
788 | ;;;; Agenda |
|
789 | (defvar org-agenda-overriding-header) |
|
790 | (defvar org-agenda-sorting-strategy) |
|
791 | (defvar org-agenda-restrict) |
|
792 | (defvar org-agenda-restrict-begin) |
|
793 | (defvar org-agenda-restrict-end) |
|
794 | ||
795 | ;;;###autoload |
|
796 | (defun org-agenda-reschedule-to-today () |
|
797 | (interactive) |
|
798 | (flet ((org-read-date (&rest rest) (current-time))) |
|
34 | 799 | (call-interactively 'org-agenda-schedule))) |
21 | 800 | |
801 | ;; Patch org-mode to use vertical splitting |
|
802 | (defadvice org-prepare-agenda (after org-fix-split) |
|
803 | (toggle-window-split)) |
|
804 | (ad-activate 'org-prepare-agenda) |
|
805 | ||
806 | (add-hook 'org-agenda-mode-hook (lambda () (hl-line-mode 1))) |
|
807 | ||
808 | (defun org-agenda-log-mode-colorize-block () |
|
809 | "Set different line spacing based on clock time duration." |
|
810 | (save-excursion |
|
811 | (let* ((colors (cl-case (alist-get 'background-mode (frame-parameters)) |
|
812 | (light |
|
813 | (list "#F6B1C3" "#FFFF9D" "#BEEB9F" "#ADD5F7")) |
|
814 | (dark |
|
815 | (list "#aa557f" "DarkGreen" "DarkSlateGray" "DarkSlateBlue")))) |
|
816 | pos |
|
817 | duration) |
|
818 | (nconc colors colors) |
|
819 | (goto-char (point-min)) |
|
820 | (while (setq pos (next-single-property-change (point) 'duration)) |
|
821 | (goto-char pos) |
|
822 | (when (and (not (equal pos (point-at-eol))) |
|
823 | (setq duration (org-get-at-bol 'duration))) |
|
824 | ;; larger duration bar height |
|
825 | (let ((line-height (if (< duration 15) 1.0 (+ 0.5 (/ duration 30)))) |
|
826 | (ov (make-overlay (point-at-bol) (1+ (point-at-eol))))) |
|
827 | (overlay-put ov 'face `(:background ,(car colors) :foreground "black")) |
|
828 | (setq colors (cdr colors)) |
|
829 | (overlay-put ov 'line-height line-height) |
|
830 | (overlay-put ov 'line-spacing (1- line-height)))))))) |
|
831 | ||
832 | (add-hook 'org-agenda-finalize-hook #'org-agenda-log-mode-colorize-block) |
|
833 | ||
834 | ;;;###autoload |
|
835 | (defun org-agenda-current-subtree-or-region (only-todos) |
|
836 | "Display an agenda view for the current subtree or region. |
|
837 | With prefix, display only TODO-keyword items." |
|
838 | (interactive "P") |
|
839 | (let ((starting-point (point)) |
|
840 | header) |
|
841 | (with-current-buffer (or (buffer-base-buffer (current-buffer)) |
|
842 | (current-buffer)) |
|
843 | (if (use-region-p) |
|
844 | (progn |
|
845 | (setq header "Region") |
|
846 | (put 'org-agenda-files 'org-restrict (list (buffer-file-name (current-buffer)))) |
|
847 | (setq org-agenda-restrict (current-buffer)) |
|
848 | (move-marker org-agenda-restrict-begin (region-beginning)) |
|
849 | (move-marker org-agenda-restrict-end |
|
850 | (save-excursion |
|
851 | ;; If point is at beginning of line, include |
|
852 | ;; heading on that line by moving forward 1. |
|
853 | (goto-char (1+ (region-end))) |
|
854 | (org-end-of-subtree)))) |
|
855 | ;; No region; restrict to subtree. |
|
856 | (save-excursion |
|
857 | (save-restriction |
|
858 | ;; In case the command was called from an indirect buffer, set point |
|
859 | ;; in the base buffer to the same position while setting restriction. |
|
860 | (widen) |
|
861 | (goto-char starting-point) |
|
862 | (setq header "Subtree") |
|
863 | (org-agenda-set-restriction-lock)))) |
|
864 | ;; NOTE: Unlike other agenda commands, binding `org-agenda-sorting-strategy' |
|
865 | ;; around `org-search-view' seems to have no effect. |
|
866 | (let ((org-agenda-sorting-strategy '(priority-down timestamp-up)) |
|
867 | (org-agenda-overriding-header header)) |
|
868 | (org-search-view (if only-todos t nil) "*")) |
|
869 | (org-agenda-remove-restriction-lock t) |
|
870 | (message nil)))) |
|
871 | ||
24 | 872 | ;;; Tempo |
873 | (setq tempo-interactive t) |
|
26 | 874 | |
875 | (provide 'default) |
|
27 | 876 | ;; default.el ends here |