changelog shortlog graph tags branches changeset files revisions annotate raw help

Mercurial > core / emacs/default.el

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