Blob


1 ;; get rid of custom from my init file
2 (setq custom-file "~/.emacs.d/emacs-custom.el")
3 (load custom-file)
5 (setq-default abbrev-mode t)
6 (setq abbrev-file-name
7 (expand-file-name "~/dotsnew/emacs/abbrev_defs"))
9 (defconst op/backup-dir
10 (expand-file-name "backups" user-emacs-directory))
11 (unless (file-exists-p op/backup-dir)
12 (make-directory op/backup-dir))
13 (setq backup-directory-alist `(("." . ,op/backup-dir)))
15 (setq use-dialog-box nil
16 x-stretch-cursor t
17 require-final-newline t
18 visible-bell nil
19 load-prefer-newer t
20 tab-bar-show 1
21 enable-recursive-minibuffers t
22 imenu-auto-rescan 1
23 use-short-answers t
24 next-error-message-highlight t
25 read-minibuffer-restore-windows nil
26 isearch-allow-motion t
27 calc-make-windows-dedicated t
28 user-mail-address "op@omarpolo.com")
30 (setq completion-ignore-case t
31 read-file-name-completion-ignore-case t
32 read-buffer-completion-ignore-case t)
34 (define-key global-map (kbd "C-x C-b") #'ibuffer)
35 (define-key global-map (kbd "M-g i") #'imenu)
37 (defun op/imenu ()
38 "Just like `imenu', but always flattened!"
39 (interactive ))
41 ;; mg-like
42 (define-key minibuffer-mode-map (kbd "C-w") #'backward-kill-word)
44 (defun op/reverse-other-window ()
45 "Like `other-window', but reverse."
46 (interactive "")
47 (other-window -1))
48 (define-key global-map (kbd "C-x O") #'op/reverse-other-window)
50 (setq uniquify-buffer-name-style 'forward
51 uniquify-strip-common-suffix t)
53 (setq-default scroll-up-aggressively 0.0
54 scroll-down-aggressively 0.0
55 scroll-preserve-screen-position t
56 next-screen-context-lines 1)
58 (define-key global-map (kbd "M-z") #'zap-up-to-char)
60 (require 'whitespace)
61 (setq whitespace-style '(face trailing)
62 backward-delete-char-untabify-method 'hungry
63 tab-always-indent 'complete
64 tab-width 8
65 sentence-end-double-space t)
66 (setq-default indent-tabs-mode t)
68 (defun op/enable-tabs ()
69 "Enable `indent-tabs-mode' in the current buffer."
70 (interactive)
71 (setq-local indent-tabs-mode t))
73 (defun op/disable-tabs ()
74 "Disable `indent-tabs-mode' in the current buffer."
75 (interactive)
76 (setq-local indent-tabs-mode nil))
78 (add-hook 'conf-mode-hook #'op/enable-tabs)
79 (add-hook 'text-mode-hook #'op/enable-tabs)
80 (add-hook 'prog-mode-hook #'op/enable-tabs)
81 (add-hook 'prog-mode-hook #'whitespace-mode)
82 (add-hook 'text-mode-hook #'whitespace-mode)
84 (dolist (hook '(emacs-lisp-mode-hook
85 clojure-mode-hook
86 clojurescript-mode-hook
87 clojurec-mode-hook
88 scss-mode-hook))
89 (add-hook hook #'op/disable-tabs))
91 (with-eval-after-load 'log-edit
92 (add-hook 'log-edit-mode #'auto-fill-mode))
94 ;; free the c-z binding
95 (define-key global-map (kbd "C-z") nil)
96 (define-key global-map (kbd "C-z V") #'variable-pitch-mode)
97 (define-key global-map (kbd "C-z n") #'display-line-numbers-mode)
99 (define-key global-map (kbd "M-SPC") #'cycle-spacing)
100 (define-key global-map (kbd "M-u") #'upcase-dwim)
101 (define-key global-map (kbd "M-l") #'downcase-dwim)
102 (define-key global-map (kbd "M-c") #'capitalize-dwim)
104 (let ((font "-misc-fixed-medium-r-semicondensed--13-120-75-75-c-60-iso10646-1"))
105 (set-frame-font font nil t)
106 (add-to-list 'default-frame-alist `(font . ,font)))
108 ;; fix the emojis too
109 (set-fontset-font t 'emoji '("Noto Emoji" . "iso10646-1")
110 nil 'prepend)
112 ;; some cool stuff
113 (save-place-mode +1)
114 (savehist-mode +1)
115 (setq history-delete-duplicates t
116 history-length 1000
117 savehist-save-minibuffer-history t)
118 (electric-pair-mode +1)
120 (define-key global-map (kbd "M-/") #'hippie-expand)
121 (setq hippie-expand-try-functions-list
122 '(try-expand-dabbrev
123 try-expand-dabbrev-all-buffers
124 try-expand-dabbrev-from-kill
125 try-complete-file-name-partially
126 try-complete-file-name
127 try-expand-all-abbrevs
128 try-expand-list
129 try-expand-line
130 try-complete-lisp-symbol-partially
131 try-complete-lisp-symbol))
133 (setq isearch-lazy-count t
134 search-whitespace-regexp ".*?"
135 isearch-allow-scroll 'unlimited)
137 (defun op/buffer-to-side-window (place)
138 "Place the current buffer in the side window at PLACE."
139 (interactive (list (intern
140 (completing-read "Which side: "
141 '(top left right bottom)))))
142 (let ((buf (current-buffer)))
143 (display-buffer-in-side-window
144 buf `((window-height . 0.15)
145 (side . ,place)
146 (slot . -1)
147 (window-parameters . ((no-delete-other-windows . t)))))
148 (delete-window)))
150 (defun op/visit-new-migration-file (name)
151 "Visit a new SQL migration file named after NAME."
152 (interactive "Mname: ")
153 (let* ((name (replace-regexp-in-string " " "-" (string-trim name)))
154 (f (format "%s-%s.sql"
155 (format-time-string "%Y%m%d%H%M")
156 name)))
157 (find-file f)))
159 (defun op/fill-or-unfill (fn &optional justify region)
160 "Meant to be an adviced :around `fill-paragraph'.
161 FN is the original `fill-column'. If `last-command' is
162 `fill-paragraph', unfill it, fill it otherwise. Inspired from a
163 post on endless parentheses. Optional argument JUSTIFY and
164 REGION are passed to `fill-paragraph'."
165 (let ((fill-column
166 (if (eq last-command 'fill-paragraph)
167 (progn (setq this-command nil)
168 (point-max))
169 fill-column)))
170 (funcall fn justify region)))
171 (advice-add 'fill-paragraph :around #'op/fill-or-unfill)
173 (defmacro op/deftranspose (name scope key doc)
174 "Macro to produce transposition functions.
175 NAME is the function's symbol. SCOPE is the text object to
176 operate on. Optional DOC is the function's docstring.
178 Transposition over an active region will swap the object at
179 mark (region beginning) with the one at point (region end).
181 It can optionally define a key for the defined function in the
182 `global-map' if KEY is passed.
184 Originally from protesilaos' dotemacs."
185 (declare (indent defun))
186 `(progn
187 (defun ,name (arg)
188 ,doc
189 (interactive "p")
190 (let ((x (intern (format "transpose-%s" ,scope))))
191 (if (use-region-p)
192 (funcall x 0)
193 (funcall x arg))))
194 ,(when key
195 `(define-key global-map (kbd ,key) #',name))))
197 (op/deftranspose op/transpose-lines "lines" "C-x C-t"
198 "Transpose lines or swap over active region.")
200 (op/deftranspose op/transpose-paragraphs "paragraphs" "C-S-t"
201 "Transpose paragraph or swap over active region.")
203 (op/deftranspose op/transpose-sentences "sentences" "C-x M-t"
204 "Transpose sentences or swap over active region.")
206 (op/deftranspose op/transpose-sexps "sexps" "C-M-t"
207 "Transpose sexps or swap over active region.")
209 (op/deftranspose op/transpose-words "words" "M-t"
210 "Transpose words or swap over active region.")
212 (defun op/narrow-or-widen-dwim (p)
213 "Widen if the buffer is narrowed, narrow-dwim otherwise.
214 Dwim means: region, org-src-block, org-subtree or defun,
215 whichever applies first. Narrowing to org-src-blocks actually
216 calls `org-edit-src-code'.
218 With prefix P, don't widen, just narrow even if buffer is already
219 narrowed. With P being -, narrow to page instead of to defun.
221 Taken from endless parentheses."
222 (interactive "P")
223 (declare (interactive-only))
224 (cond ((and (buffer-narrowed-p) (not p)) (widen))
225 ((region-active-p)
226 (narrow-to-region (region-beginning)
227 (region-end)))
228 ((derived-mode-p 'org-mode)
229 ;; `org-edit-src-code' isn't a real narrowing
230 (cond ((ignore-errors (org-edit-src-code) t))
231 ((ignore-errors (org-narrow-to-block) t))
232 (t (org-narrow-to-subtree))))
233 ((eql p '-) (narrow-to-page))
234 (t (narrow-to-defun))))
236 (define-key global-map (kbd "C-c w") #'op/narrow-or-widen-dwim)
238 (with-eval-after-load 'dired
239 (add-hook 'dired-mode-hook #'dired-hide-details-mode)
240 (add-hook 'dired-mode-hook #'dired-omit-mode)
242 (define-key dired-mode-map (kbd "C-c w") #'wdired-change-to-wdired-mode)
244 (require 'dired-x)
245 (setq dired-listing-switches "-lahF"
246 dired-dwim-target t
247 dired-deletion-confirmer #'y-or-n-p
248 dired-do-revert-buffer t))
250 ;; just like telescope!
251 (with-eval-after-load 'diff-mode
252 (define-key diff-mode-map (kbd "M-SPC") #'scroll-down-command))
254 (with-eval-after-load 'elisp-mode
255 (add-hook 'emacs-lisp-mode-hook #'checkdoc-minor-mode)
256 (add-hook 'emacs-lisp-mode-hook #'prettify-symbols-mode)
257 (let ((map emacs-lisp-mode-map))
258 (define-key map (kbd "C-c C-k") #'eval-buffer)
259 (define-key map (kbd "C-c k") #'op/ert-all)
260 (define-key map (kbd "C-c C-z") #'op/ielm-repl)))
262 (with-eval-after-load 'help
263 (add-hook 'help-mode-hook #'visual-line-mode))
265 ;; add melpa
266 (add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t)
268 ;; packages that i want to be installed
269 (dolist (pkg '(vc-got pdf-tools eglot nameless sly cider go-mode web-mode
270 lua-mode markdown-mode yaml-mode gemini-mode elfeed
271 form-feed shackle embark consult mct puni))
272 (unless (package-installed-p pkg)
273 (message "Installing %s" pkg)
274 (package-install pkg)))
276 (global-form-feed-mode +1)
278 (add-hook 'text-mode-hook #'puni-mode)
279 (add-hook 'prog-mode-hook #'puni-mode)
280 (define-key puni-mode-map (kbd "C-)") #'puni-slurp-forward)
281 (define-key puni-mode-map (kbd "C-(") #'puni-barf-forward)
283 (setq completion-styles '(basic substring initials flex partial-completion))
285 (require 'consult) ;; some stuff lacks an autoload and i don't want to debug it
287 (cl-loop for (key . func) in '(("C-x :" . consult-complex-command)
288 ("C-x b" . consult-buffer)
289 ("C-x 4 b" . consult-buffer-other-window)
290 ("C-x 5 b" . consult-buffer-other-frame)
291 ("C-x r b" . consult-bookmark)
292 ("C-x p b" . consult-project-buffer)
293 ("M-y" . consult-yank-pop)
294 ("M-g g" . consult-goto-line)
295 ("M-g M-g" . consult-goto-line)
296 ("M-g m" . consult-mark)
297 ("M-g i" . consult-imenu)
298 ("M-s l" . consult-line)
299 ("M-s L" . consult-line-multi)
300 ("M-s m" . consult-multi-occur))
301 do (define-key global-map (kbd key) func))
302 (add-hook 'completion-list-mode-hook #'consult-preview-at-point-mode)
304 (setq completions-detailed t)
305 (mct-minibuffer-mode +1)
306 (mct-region-mode +1)
308 ;; override the binding for the annoying mct-backward-updir.
309 (define-key mct-minibuffer-local-filename-completion-map
310 (kbd "DEL") #'backward-delete-char)
312 (setq mct-remove-shadowed-file-names t
313 mct-completions-format 'one-column
314 mct-completion-passlist '(Info-goto-node
315 Info-index
316 Info-menu
317 vc-retrieve-tag
318 imenu
319 file
320 buffer
321 kill-ring
322 consult-buffer))
324 (with-eval-after-load 'go-mode
325 (add-hook 'go-mode-hook #'subword-mode))
327 (with-eval-after-load 'eglot
328 (define-key eglot-mode-map (kbd "<f1>") #'eglot-code-actions)
329 (define-key eglot-mode-map (kbd "<f2>") #'eglot-format)
330 (add-to-list 'eglot-ignored-server-capabilites
331 :documentHighlightProvider)
332 (add-to-list 'eglot-server-programs
333 '(c-mode . ("clangd" "--header-insertion=never"))))
335 (add-hook 'emacs-lisp-mode #'nameless-mode)
336 (with-eval-after-load 'nameless
337 (setq nameless-private-prefix t
338 nameless-affect-indentation-and-filling nil)
339 (define-key emacs-lisp-mode-map (kbd "_") #'nameless-insert-name-or-self-insert))
341 (add-to-list 'auto-mode-alist '("\\.html\\'" . web-mode))
342 (with-eval-after-load 'web-mode
343 (setq web-mode-markup-indent-offset 2
344 web-mode-css-indent-offset 2
345 web-mode-style-padding 0
346 web-mode-enable-engine-detection t)
347 (add-hook 'web-mode-hook #'op/disable-tabs)
349 ;; fix .dir-locals.el
350 (defun op/web-mode-fix-dir-locals ()
351 (when (derived-mode-p major-mode 'web-mode)
352 (web-mode-guess-engine-and-content-type)))
353 (add-hook 'hack-local-variables-hook #'op/web-mode-fix-dir-locals))
355 (with-eval-after-load 'css-mode
356 (add-hook 'css-mode-hook #'op/disable-tabs))
358 (with-eval-after-load 'flymake
359 (define-key prog-mode-map (kbd "C-c ! n") #'flymake-goto-next-error)
360 (define-key prog-mode-map (kbd "C-c ! p") #'flymake-goto-prev-error))
362 (with-eval-after-load 'cc-mode
363 (setq c-basic-offset 8
364 c-default-style "K&R")
365 (dolist (hook '(c-mode-hook c++-mode-hook))
366 (add-hook hook #'abbrev-mode)
367 (add-hook hook #'subword-mode))
368 (defun op/c-indent ()
369 (interactive)
370 (c-set-offset 'arglist-intro '+)
371 (c-set-offset 'arglist-cont-nonempty '*))
372 (add-hook 'c-mode-hook #'op/c-indent)
373 ;; TODO: improve it!
374 (defun op/c-add-include (path &optional localp)
375 "Include PATH at the start of the file.
376 If LOCALP is non-nil, the include will be \"local\"."
377 (interactive "Mheader to include: \nP")
378 (save-excursion
379 (let ((re (if localp
380 "^#[ \t]*include[ \t]*\""
381 "^#[ \t]*include[ \t]*<"))
382 (ignore-re "^#include \"compat.h\"")
383 start)
384 (goto-char (point-min))
385 (while (not (or (and (looking-at re)
386 (not (looking-at ignore-re)))
387 (eobp)))
388 (forward-line))
389 (when (eobp)
390 (error "Don't know where to insert the header"))
391 (open-line 1)
392 (insert "#include " (if localp "\"\"" "<>"))
393 (backward-char)
394 (insert path)
395 (move-beginning-of-line 1)
396 (setq start (point))
397 (forward-line)
398 (while (and (looking-at re)
399 (not (eobp)))
400 (forward-line))
401 (sort-lines nil start (point)))))
402 (define-key c-mode-map (kbd "C-c C-a") #'op/c-add-include))
404 (with-eval-after-load 'perl-mode
405 (setq perl-indent-level 8))
407 (with-eval-after-load 'sh-script
408 (setq sh-basic-offset 8
409 sh-indent-after-loop-construct 8
410 sh-indent-after-continuation nil))
414 (setq eshell-hist-ignoredups t)
416 (defun op/eshell-bufname (dir)
417 (concat "*eshell " (expand-file-name dir) "*"))
419 (defun op/eshell (arg)
420 "Run or jump to eshell in current project.
421 If called with prefix argument ARG always create a new eshell
422 buffer."
423 (interactive "P")
424 (let* ((proj (project-current))
425 (dir (if (and proj (not arg))
426 (project-root proj)
427 default-directory))
428 (default-directory dir)
429 (eshell-buffer-name (let ((name (op/eshell-bufname dir)))
430 (if arg
431 (generate-new-buffer name)
432 name))))
433 (eshell)))
434 (define-key global-map (kbd "C-c e") #'op/eshell)
436 (with-eval-after-load 'eshell
437 (setq eshell-save-history-on-exit t
438 eshell-history-size 1024
440 eshell-compl-dir-ignore
441 "\\`\\(\\.\\.?\\|CVS\\|\\.svn\\|\\.git\\|\\.got\\)/\\'")
443 (defun op/eshell-after-cd (&rest _)
444 (rename-buffer (op/eshell-bufname default-directory) t))
446 (advice-add #'eshell/cd :after #'op/eshell-after-cd))
448 (with-eval-after-load 'esh-mode
449 (defun op/clear-eshell ()
450 (interactive "")
451 (let ((inhibit-read-only t))
452 (erase-buffer)
453 (eshell-send-input)))
455 (define-key eshell-command-map (kbd "M-o") #'op/clear-eshell))
458 ;; sndio.el
459 (unless (package-installed-p 'sndio)
460 (package-install-file "~/w/sndio.el/sndio.el"))
463 ;; saturn
464 (unless (package-installed-p 'saturn)
465 (package-install-file "~/w/saturn/GUI/saturn.el"))
468 ;; simple-pass
469 (unless (package-installed-p 'simple-pass)
470 (package-install-file "~/.emacs.d/simple-pass.el"))
471 (define-key global-map (kbd "C-z p") #'simple-pass-copy)
475 ;; elfeed
477 (define-key global-map (kbd "C-x w") #'elfeed)
478 (with-eval-after-load 'elfeed
479 (define-key elfeed-show-mode-map (kbd "q") #'delete-window)
480 (define-key elfeed-show-mode-map (kbd "S-SPC") #'scroll-down-command)
481 (define-key elfeed-show-mode-map (kbd "M-SPC") #'scroll-down-command)
482 (setq elfeed-show-entry-switch #'pop-to-buffer
483 elfeed-feeds
484 '("https://undeadly.org/cgi?action=rss&full=yes&items=10"
485 "http://www.tedunangst.com/flak/rss"
486 "https://www.dragonflydigest.com/feed"
487 "https://www.mirbsd.org/news.rss"
488 "https://www.mirbsd.org/announce.rss"
489 "https://bentsukun.ch/index.xml"
490 "https://drewdevault.com/feed.xml"
491 "https://www.cambus.net/atom.xml"
492 "https://dataswamp.org/~solene/rss.xml"
493 "https://briancallahan.net/blog/feed.xml"
494 "https://www.poolp.org/index.xml"
495 "https://jcs.org/rss"
496 "https://sanctum.geek.nz/arabesque/feed/"
497 "https://tech.toryanderson.com/"
498 "https://alexschroeder.ch/wiki?action=journal;search=-tag:rpg -tag:rsp;lang=en;title=English Diary without RPG Pages"
499 "http://boston.conman.org/bostondiaries.rss"
500 "https://emacsninja.com/feed.atom"
501 "https://bsdly.blogspot.com/feeds/posts/default"
502 "https://crawshaw.io/atom.xml"
503 "https://nullprogram.com/feed/"
504 "http://pragmaticemacs.com/feed/"
505 "https://emacsnotes.wordpress.com/feed/"
506 "https://metaredux.com/feed.xml"
507 "https://emacsredux.com/atom.xml"
508 "https://endlessparentheses.com/atom.xml"
509 "https://www.masteringemacs.org/feed"
510 "https://cestlaz.github.io/rss.xml"
511 "https://utcc.utoronto.ca/~cks/space/blog/?atom"
512 "https://irreal.org/blog/?feed=rss2"
513 "https://jao.io/blog/rss.xml"
514 "https://planet.lisp.org/rss20.xml"
515 "https://insideclojure.org/feed.xml"
516 "https://tech.toryanderson.com/index.xml"
517 "https://vermaden.wordpress.com/feed/"
518 "https://www.arp242.net/feed.xml"
519 "https://tymoon.eu/api/reader/atom"
520 "https://venam.nixers.net/blog/feed.xml"
521 "https://www.omarpolo.com/rss.xml"
522 "https://owarisubs.lacumpa.biz/feed/"
523 "https://asenshi.moe/feed/"
524 "https://godotengine.org/rss.xml"
526 "https://adventofcomputing.libsyn.com/rss"
528 "https://github.com/go-gitea/gitea/releases.atom"
530 "https://nitter.pussthecat.org/NanoRaptor/rss"
532 "https://github.com/yshui/picom/releases.atom"
533 "https://github.com/vslavik/poedit/releases.atom"
534 "https://github.com/TokTok/c-toxcore/releases.atom"
535 "https://github.com/alexander-akhmetov/python-telegram/releases.atom"
536 "https://github.com/paul-nameless/tg/releases.atom"
537 "https://github.com/YACReader/yacreader/releases.atom"
538 "https://github.com/luarocks/luarocks/releases.atom"
539 "https://github.com/okbob/pspg/releases.atom"
540 "https://github.com/taisei-project/taisei/releases.atom"
541 "https://github.com/recp/cglm/releases.atom"
542 "https://github.com/SCons/scons/releases.atom"
543 "https://git.sr.ht/~rjarry/aerc/refs/rss.xml"
545 "https://causal.agency/list/pounce.atom"
547 "https://www.crimsonmagic.me/feed/"
548 "https://fullybookedtls.wordpress.com/feed/"
550 "https://draculadaily.substack.com/feed")))
552 (setq shackle-default-rule nil
553 shackle-rules
554 (let ((repls "\\*\\(cider-repl\\|sly-mrepl\\|ielm\\)")
555 (godot "\\*godot - .*\\*")
556 (vcs "\\*\\(Flymake\\|Package-Lint\\|vc-\\(git\\|got\\) :\\).*")
557 (elfeed "\\*elfeed-entry\\*")
558 (vmd "\\*vmd console .*"))
559 `((compilation-mode :noselect t
560 :align above
561 :size 0.2)
562 ("*Async Shell Command*" :ignore t)
563 (,repls :regexp t
564 :align below
565 :size 0.3)
566 (,godot :regexp t
567 :align t
568 :size 0.3)
569 (occur-mode :select t
570 :align right
571 :size 0.3)
572 (diff-mode :select t)
573 (help-mode :select t
574 :align left
575 :size 0.3)
576 (,vcs :regexp t
577 :align above
578 :size 0.15
579 :select t)
580 (,elfeed :regexp t
581 :align t
582 :select t
583 :size 0.75)
584 (,vmd :regexp t
585 :align below
586 :select t
587 :size 0.3))))
588 (shackle-mode +1)
590 (define-key global-map (kbd "M-g e") #'embark-act)