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 ;; I don't like how compile uses `make -k' by default, I want to stop
31 ;; on errors / warnings.
32 (setq compile-command "make")
34 ;; "diff refinement", i.e. highlighting the changes in a more granular
35 ;; way, is quite awful to have it enabled by default. sometimes is
36 ;; useful, but for me it's more of a visual noise most of the times.
37 (setq diff-refine nil)
39 ;; disable also the syntax highlighting in the diff buffers
40 (setq diff-font-lock-syntax nil)
42 (define-key global-map (kbd "C-x C-b") #'ibuffer)
43 (define-key global-map (kbd "M-g i") #'imenu)
45 (defun op/imenu ()
46 "Just like `imenu', but always flattened!"
47 (interactive ))
49 ;; mg-like
50 (define-key minibuffer-mode-map (kbd "C-w") #'backward-kill-word)
52 ;; niceties for the standard completion
53 (setq tab-always-indent 'complete
54 completion-ignore-case t
55 read-file-name-completion-ignore-case t
56 read-buffer-completion-ignore-case t
57 completion-auto-help 'always
58 completion-auto-select 'second-tab
59 completions-max-height 10
60 completions-format 'horizontal
61 completions-header-format ""
62 completion-show-help nil)
64 (define-key minibuffer-local-map (kbd "C-p") #'minibuffer-previous-completion)
65 (define-key minibuffer-local-map (kbd "C-n") #'minibuffer-next-completion)
67 (define-key completion-in-region-mode-map (kbd "C-p")
68 #'minibuffer-previous-completion)
69 (define-key completion-in-region-mode-map (kbd "C-n")
70 #'minibuffer-next-completion)
72 (define-key completion-in-region-mode-map (kbd "RET")
73 #'minibuffer-choose-completion)
75 (defun op/reverse-other-window ()
76 "Like `other-window', but reverse."
77 (interactive "")
78 (other-window -1))
79 (define-key global-map (kbd "C-x O") #'op/reverse-other-window)
81 (define-key global-map (kbd "C-x v f") #'vc-pull)
83 (setq uniquify-buffer-name-style 'forward
84 uniquify-strip-common-suffix t)
86 (setq-default scroll-up-aggressively 0.0
87 scroll-down-aggressively 0.0
88 scroll-preserve-screen-position t
89 next-screen-context-lines 1)
91 (define-key global-map (kbd "M-Z") #'zap-up-to-char)
93 (require 'whitespace)
94 (setq whitespace-style '(face trailing)
95 backward-delete-char-untabify-method 'hungry
96 tab-width 8
97 sentence-end-double-space t)
98 (setq-default indent-tabs-mode t)
100 (defun op/enable-tabs ()
101 "Enable `indent-tabs-mode' in the current buffer."
102 (interactive)
103 (setq-local indent-tabs-mode t))
105 (defun op/disable-tabs ()
106 "Disable `indent-tabs-mode' in the current buffer."
107 (interactive)
108 (setq-local indent-tabs-mode nil))
110 (add-hook 'conf-mode-hook #'op/enable-tabs)
111 (add-hook 'text-mode-hook #'op/enable-tabs)
112 (add-hook 'prog-mode-hook #'op/enable-tabs)
113 (add-hook 'prog-mode-hook #'whitespace-mode)
114 (add-hook 'text-mode-hook #'whitespace-mode)
116 (dolist (hook '(emacs-lisp-mode-hook
117 js-mode-hook
118 clojure-mode-hook
119 clojurescript-mode-hook
120 clojurec-mode-hook
121 scss-mode-hook))
122 (add-hook hook #'op/disable-tabs))
124 (with-eval-after-load 'log-edit
125 (add-hook 'log-edit-mode #'auto-fill-mode))
127 ;; free the c-z binding
128 (define-key global-map (kbd "C-z") nil)
129 (define-key global-map (kbd "C-z V") #'variable-pitch-mode)
130 (define-key global-map (kbd "C-z n") #'display-line-numbers-mode)
132 (define-key global-map (kbd "M-SPC") #'cycle-spacing)
133 (define-key global-map (kbd "M-u") #'upcase-dwim)
134 (define-key global-map (kbd "M-l") #'downcase-dwim)
135 (define-key global-map (kbd "M-c") #'capitalize-dwim)
137 (let ((font
138 ;; "-misc-fixed-medium-r-semicondensed--13-120-75-75-c-60-iso10646-1"
139 "Spleen"
140 ))
141 (set-frame-font font nil t)
142 (add-to-list 'default-frame-alist `(font . ,font)))
144 ;; fix the emojis too
145 (set-fontset-font t 'emoji '("Noto Emoji" . "iso10646-1")
146 nil 'prepend)
148 ;; some cool stuff
149 (save-place-mode +1)
150 ;(savehist-mode +1)
151 (setq history-delete-duplicates t
152 history-length 1000
153 savehist-save-minibuffer-history t)
154 (electric-pair-mode +1)
156 (define-key global-map (kbd "M-/") #'hippie-expand)
157 (setq hippie-expand-try-functions-list
158 '(try-expand-dabbrev
159 try-expand-dabbrev-all-buffers
160 try-expand-dabbrev-from-kill
161 try-complete-file-name-partially
162 try-complete-file-name
163 try-expand-all-abbrevs
164 try-expand-list
165 try-expand-line
166 try-complete-lisp-symbol-partially
167 try-complete-lisp-symbol))
169 (setq isearch-lazy-count t
170 search-whitespace-regexp ".*?"
171 isearch-allow-scroll 'unlimited)
173 (defun op/buffer-to-side-window (place)
174 "Place the current buffer in the side window at PLACE."
175 (interactive (list (intern
176 (completing-read "Which side: "
177 '(top left right bottom)))))
178 (let ((buf (current-buffer)))
179 (display-buffer-in-side-window
180 buf `((window-height . 0.15)
181 (side . ,place)
182 (slot . -1)
183 (window-parameters . ((no-delete-other-windows . t)))))
184 (delete-window)))
186 (defun op/visit-new-migration-file (name)
187 "Visit a new SQL migration file named after NAME."
188 (interactive "Mname: ")
189 (let* ((name (replace-regexp-in-string " " "-" (string-trim name)))
190 (f (format "%s-%s.sql"
191 (format-time-string "%Y%m%d%H%M")
192 name)))
193 (find-file f)))
195 (defun op/fill-or-unfill (fn &optional justify region)
196 "Meant to be an adviced :around `fill-paragraph'.
197 FN is the original `fill-column'. If `last-command' is
198 `fill-paragraph', unfill it, fill it otherwise. Inspired from a
199 post on endless parentheses. Optional argument JUSTIFY and
200 REGION are passed to `fill-paragraph'."
201 (let ((fill-column
202 (if (eq last-command 'fill-paragraph)
203 (progn (setq this-command nil)
204 (point-max))
205 fill-column)))
206 (funcall fn justify region)))
207 (advice-add 'fill-paragraph :around #'op/fill-or-unfill)
209 (defmacro op/deftranspose (name scope key doc)
210 "Macro to produce transposition functions.
211 NAME is the function's symbol. SCOPE is the text object to
212 operate on. Optional DOC is the function's docstring.
214 Transposition over an active region will swap the object at
215 mark (region beginning) with the one at point (region end).
217 It can optionally define a key for the defined function in the
218 `global-map' if KEY is passed.
220 Originally from protesilaos' dotemacs."
221 (declare (indent defun))
222 `(progn
223 (defun ,name (arg)
224 ,doc
225 (interactive "p")
226 (let ((x (intern (format "transpose-%s" ,scope))))
227 (if (use-region-p)
228 (funcall x 0)
229 (funcall x arg))))
230 ,(when key
231 `(define-key global-map (kbd ,key) #',name))))
233 (op/deftranspose op/transpose-lines "lines" "C-x C-t"
234 "Transpose lines or swap over active region.")
236 (op/deftranspose op/transpose-paragraphs "paragraphs" "C-S-t"
237 "Transpose paragraph or swap over active region.")
239 (op/deftranspose op/transpose-sentences "sentences" "C-x M-t"
240 "Transpose sentences or swap over active region.")
242 (op/deftranspose op/transpose-sexps "sexps" "C-M-t"
243 "Transpose sexps or swap over active region.")
245 (op/deftranspose op/transpose-words "words" "M-t"
246 "Transpose words or swap over active region.")
248 (defun op/narrow-or-widen-dwim (p)
249 "Widen if the buffer is narrowed, narrow-dwim otherwise.
250 Dwim means: region, org-src-block, org-subtree or defun,
251 whichever applies first. Narrowing to org-src-blocks actually
252 calls `org-edit-src-code'.
254 With prefix P, don't widen, just narrow even if buffer is already
255 narrowed. With P being -, narrow to page instead of to defun.
257 Taken from endless parentheses."
258 (interactive "P")
259 (declare (interactive-only))
260 (cond ((and (buffer-narrowed-p) (not p)) (widen))
261 ((region-active-p)
262 (narrow-to-region (region-beginning)
263 (region-end)))
264 ((derived-mode-p 'org-mode)
265 ;; `org-edit-src-code' isn't a real narrowing
266 (cond ((ignore-errors (org-edit-src-code) t))
267 ((ignore-errors (org-narrow-to-block) t))
268 (t (org-narrow-to-subtree))))
269 ((eql p '-) (narrow-to-page))
270 (t (narrow-to-defun))))
272 (define-key global-map (kbd "C-c w") #'op/narrow-or-widen-dwim)
274 (with-eval-after-load 'dired
275 (add-hook 'dired-mode-hook #'dired-hide-details-mode)
276 (add-hook 'dired-mode-hook #'dired-omit-mode)
278 (define-key dired-mode-map (kbd "C-c w") #'wdired-change-to-wdired-mode)
280 (require 'dired-x)
281 (setq dired-listing-switches "-lahF"
282 dired-dwim-target t
283 dired-deletion-confirmer #'y-or-n-p
284 dired-do-revert-buffer t))
286 ;; just like telescope!
287 (with-eval-after-load 'diff-mode
288 (define-key diff-mode-map (kbd "M-SPC") #'scroll-down-command))
290 (with-eval-after-load 'elisp-mode
291 (add-hook 'emacs-lisp-mode-hook #'checkdoc-minor-mode)
292 (add-hook 'emacs-lisp-mode-hook #'prettify-symbols-mode)
293 (let ((map emacs-lisp-mode-map))
294 (define-key map (kbd "C-c C-k") #'eval-buffer)
295 (define-key map (kbd "C-c k") #'op/ert-all)
296 (define-key map (kbd "C-c C-z") #'op/ielm-repl)))
298 (with-eval-after-load 'help
299 (add-hook 'help-mode-hook #'visual-line-mode))
301 ;; add melpa
302 (add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t)
304 ;; packages that i want to be installed
305 (dolist (pkg '(vc-got eglot sly cider go-mode web-mode lua-mode
306 markdown-mode yaml-mode gemini-mode
307 form-feed shackle puni orderless
308 rotate vc-fossil flimenu howm))
309 (unless (package-installed-p pkg)
310 (message "Installing %s" pkg)
311 (package-install pkg)))
313 (global-form-feed-mode +1)
314 (flimenu-global-mode +1)
316 (add-hook 'text-mode-hook #'puni-mode)
317 (add-hook 'prog-mode-hook #'puni-mode)
318 (define-key puni-mode-map (kbd "C-)") #'puni-slurp-forward)
319 (define-key puni-mode-map (kbd "C-(") #'puni-barf-forward)
321 ;;(setq completion-styles '(basic substring initials flex partial-completion))
322 (setq completion-styles '(orderless basic)
323 completion-category-overrides '((file (styles basic partial-completion))))
325 (setq completions-detailed t)
327 (with-eval-after-load 'cider
328 (define-key cider-repl-mode-map (kbd "C-c M-o") #'cider-repl-clear-buffer))
330 (with-eval-after-load 'go-mode
331 (add-hook 'go-mode-hook #'subword-mode))
333 (with-eval-after-load 'tcl
334 (setq-default tcl-indent-level 8))
336 (with-eval-after-load 'eglot
337 (define-key eglot-mode-map (kbd "<f1>") #'eglot-code-actions)
338 (define-key eglot-mode-map (kbd "<f2>") #'eglot-format)
339 (add-to-list 'eglot-ignored-server-capabilites
340 :documentHighlightProvider)
341 (add-to-list 'eglot-server-programs
342 '(c-mode . ("clangd" "--header-insertion=never"))))
344 (add-to-list 'auto-mode-alist '("\\.html\\'" . web-mode))
345 (with-eval-after-load 'web-mode
346 (setq web-mode-markup-indent-offset 2
347 web-mode-css-indent-offset 2
348 web-mode-style-padding 0
349 web-mode-enable-engine-detection t)
350 (add-hook 'web-mode-hook #'op/disable-tabs)
352 ;; fix .dir-locals.el
353 (defun op/web-mode-fix-dir-locals ()
354 (when (derived-mode-p major-mode 'web-mode)
355 (web-mode-guess-engine-and-content-type)))
356 (add-hook 'hack-local-variables-hook #'op/web-mode-fix-dir-locals)
358 (setq web-mode-enable-auto-pairing nil))
360 (with-eval-after-load 'css-mode
361 (add-hook 'css-mode-hook #'op/disable-tabs))
363 (with-eval-after-load 'flymake
364 (define-key prog-mode-map (kbd "C-c ! n") #'flymake-goto-next-error)
365 (define-key prog-mode-map (kbd "C-c ! p") #'flymake-goto-prev-error))
367 (with-eval-after-load 'cc-mode
368 (setq c-basic-offset 8
369 c-default-style "K&R")
370 (dolist (hook '(c-mode-hook c++-mode-hook))
371 (add-hook hook #'abbrev-mode)
372 (add-hook hook #'subword-mode))
373 (defun op/c-indent ()
374 (interactive)
375 (c-set-offset 'arglist-intro '+)
376 (c-set-offset 'arglist-cont-nonempty '*)
377 (c-set-offset 'label 1))
378 (add-hook 'c-mode-hook #'op/c-indent)
379 ;; TODO: improve it!
380 (defun op/c-add-include (path &optional localp)
381 "Include PATH at the start of the file.
382 If LOCALP is non-nil, the include will be \"local\"."
383 (interactive "Mheader to include: \nP")
384 (save-excursion
385 (let ((re (if localp
386 "^#[ \t]*include[ \t]*\""
387 "^#[ \t]*include[ \t]*<"))
388 (ignore-re "^#include \"compat.h\"")
389 start)
390 (goto-char (point-min))
391 (while (not (or (and (looking-at re)
392 (not (looking-at ignore-re)))
393 (eobp)))
394 (forward-line))
395 (when (eobp)
396 (error "Don't know where to insert the header"))
397 (open-line 1)
398 (insert "#include " (if localp "\"\"" "<>"))
399 (backward-char)
400 (insert path)
401 (move-beginning-of-line 1)
402 (setq start (point))
403 (forward-line)
404 (while (and (looking-at re)
405 (not (eobp)))
406 (forward-line))
407 (sort-lines nil start (point)))))
408 (define-key c-mode-map (kbd "C-c C-a") #'op/c-add-include))
410 (with-eval-after-load 'perl-mode
411 (setq perl-indent-level 8))
413 (with-eval-after-load 'sh-script
414 (setq sh-basic-offset 8
415 sh-indent-after-loop-construct 8
416 sh-indent-after-continuation nil))
420 (setq eshell-hist-ignoredups t)
422 (defun op/eshell-bufname (dir)
423 (concat "*eshell " (expand-file-name dir) "*"))
425 (defun op/eshell (arg)
426 "Run or jump to eshell in current project.
427 If called with prefix argument ARG always create a new eshell
428 buffer."
429 (interactive "P")
430 (let* ((proj (project-current))
431 (dir (if (and proj (not arg))
432 (project-root proj)
433 default-directory))
434 (default-directory dir)
435 (eshell-buffer-name (let ((name (op/eshell-bufname dir)))
436 (if arg
437 (generate-new-buffer name)
438 name))))
439 (eshell)))
440 (define-key global-map (kbd "C-c e") #'op/eshell)
442 (with-eval-after-load 'eshell
443 (setq eshell-save-history-on-exit t
444 eshell-history-size 1024
446 eshell-compl-dir-ignore
447 "\\`\\(\\.\\.?\\|CVS\\|\\.svn\\|\\.git\\|\\.got\\)/\\'")
449 (defun op/eshell-after-cd (&rest _)
450 (rename-buffer (op/eshell-bufname default-directory) t))
452 (advice-add #'eshell/cd :after #'op/eshell-after-cd))
454 (with-eval-after-load 'esh-mode
455 (defun op/clear-eshell ()
456 (interactive "")
457 (let ((inhibit-read-only t))
458 (erase-buffer)
459 (eshell-send-input)))
461 (define-key eshell-command-map (kbd "M-o") #'op/clear-eshell))
464 ;; sndio.el
465 (unless (package-installed-p 'sndio)
466 (package-install-file "~/w/sndio.el/sndio.el"))
469 ;; saturn
470 (unless (package-installed-p 'saturn)
471 (package-install-file "~/w/saturn/GUI/saturn.el"))
474 ;; emacs-pq
475 (add-to-list 'load-path "~/build/emacs-libpq/")
476 (unless (package-installed-p 'pq)
477 (package-install-file "~/build/emacs-libpq/pq.el"))
480 ;; plass
481 (unless (package-installed-p 'plass)
482 (ignore-errors
483 (package-install-file "~/w/plass/extra/plass.el")))
485 (with-eval-after-load 'plass
486 (setq plass-filter "!2fa"
487 plass-totp-filter "2fa"))
491 (setq shackle-default-rule nil
492 shackle-rules
493 (let ((repls "\\*\\(cider-repl\\|sly-mrepl\\|ielm\\)")
494 (godot "\\*godot - .*\\*")
495 (vcs "\\*\\(Flymake\\|Package-Lint\\|vc-\\(git\\|got\\|fossil\\) :\\).*")
496 (elfeed "\\*elfeed-entry\\*")
497 (vmd "\\*vmd console .*"))
498 `(("*Async Shell Command*" :ignore t)
499 (,repls :regexp t
500 :align below
501 :size 0.3)
502 (,godot :regexp t
503 :align t
504 :size 0.3)
505 (occur-mode :select t
506 :align right
507 :size 0.3)
508 (diff-mode :select t)
509 (help-mode :select t
510 :align left
511 :size 0.3)
512 (,vcs :regexp t
513 :align above
514 :size 0.15
515 :select t)
516 (,elfeed :regexp t
517 :align t
518 :select t
519 :size 0.75)
520 (,vmd :regexp t
521 :align below
522 :select t
523 :size 0.3))))
524 (shackle-mode +1)
526 ;; (setq display-buffer-alist nil)
529 ;; rotate
530 (define-key global-map (kbd "C-c R") #'rotate-window)
531 (define-key global-map (kbd "C-c r") #'rotate-layout)
534 ;; howm
535 (require 'howm)
537 (define-key howm-menu-mode-map "\C-h" nil)
538 (define-key riffle-summary-mode-map "\C-h" nil)
539 (define-key howm-view-contents-mode-map "\C-h" nil)
541 ;; rename buffers to their title
542 (add-hook 'howm-mode-hook 'howm-mode-set-buffer-name)
543 (add-hook 'after-save-hook 'howm-mode-set-buffer-name)