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 clojure-mode-hook
118 clojurescript-mode-hook
119 clojurec-mode-hook
120 scss-mode-hook))
121 (add-hook hook #'op/disable-tabs))
123 (with-eval-after-load 'log-edit
124 (add-hook 'log-edit-mode #'auto-fill-mode))
126 ;; free the c-z binding
127 (define-key global-map (kbd "C-z") nil)
128 (define-key global-map (kbd "C-z V") #'variable-pitch-mode)
129 (define-key global-map (kbd "C-z n") #'display-line-numbers-mode)
131 (define-key global-map (kbd "M-SPC") #'cycle-spacing)
132 (define-key global-map (kbd "M-u") #'upcase-dwim)
133 (define-key global-map (kbd "M-l") #'downcase-dwim)
134 (define-key global-map (kbd "M-c") #'capitalize-dwim)
136 (let ((font
137 ;; "-misc-fixed-medium-r-semicondensed--13-120-75-75-c-60-iso10646-1"
138 "JuliaMono 8"
139 ))
140 (set-frame-font font nil t)
141 (add-to-list 'default-frame-alist `(font . ,font)))
143 ;; fix the emojis too
144 (set-fontset-font t 'emoji '("Noto Emoji" . "iso10646-1")
145 nil 'prepend)
147 ;; some cool stuff
148 (save-place-mode +1)
149 (savehist-mode +1)
150 (setq history-delete-duplicates t
151 history-length 1000
152 savehist-save-minibuffer-history t)
153 (electric-pair-mode +1)
155 (define-key global-map (kbd "M-/") #'hippie-expand)
156 (setq hippie-expand-try-functions-list
157 '(try-expand-dabbrev
158 try-expand-dabbrev-all-buffers
159 try-expand-dabbrev-from-kill
160 try-complete-file-name-partially
161 try-complete-file-name
162 try-expand-all-abbrevs
163 try-expand-list
164 try-expand-line
165 try-complete-lisp-symbol-partially
166 try-complete-lisp-symbol))
168 (setq isearch-lazy-count t
169 search-whitespace-regexp ".*?"
170 isearch-allow-scroll 'unlimited)
172 (defun op/buffer-to-side-window (place)
173 "Place the current buffer in the side window at PLACE."
174 (interactive (list (intern
175 (completing-read "Which side: "
176 '(top left right bottom)))))
177 (let ((buf (current-buffer)))
178 (display-buffer-in-side-window
179 buf `((window-height . 0.15)
180 (side . ,place)
181 (slot . -1)
182 (window-parameters . ((no-delete-other-windows . t)))))
183 (delete-window)))
185 (defun op/visit-new-migration-file (name)
186 "Visit a new SQL migration file named after NAME."
187 (interactive "Mname: ")
188 (let* ((name (replace-regexp-in-string " " "-" (string-trim name)))
189 (f (format "%s-%s.sql"
190 (format-time-string "%Y%m%d%H%M")
191 name)))
192 (find-file f)))
194 (defun op/fill-or-unfill (fn &optional justify region)
195 "Meant to be an adviced :around `fill-paragraph'.
196 FN is the original `fill-column'. If `last-command' is
197 `fill-paragraph', unfill it, fill it otherwise. Inspired from a
198 post on endless parentheses. Optional argument JUSTIFY and
199 REGION are passed to `fill-paragraph'."
200 (let ((fill-column
201 (if (eq last-command 'fill-paragraph)
202 (progn (setq this-command nil)
203 (point-max))
204 fill-column)))
205 (funcall fn justify region)))
206 (advice-add 'fill-paragraph :around #'op/fill-or-unfill)
208 (defmacro op/deftranspose (name scope key doc)
209 "Macro to produce transposition functions.
210 NAME is the function's symbol. SCOPE is the text object to
211 operate on. Optional DOC is the function's docstring.
213 Transposition over an active region will swap the object at
214 mark (region beginning) with the one at point (region end).
216 It can optionally define a key for the defined function in the
217 `global-map' if KEY is passed.
219 Originally from protesilaos' dotemacs."
220 (declare (indent defun))
221 `(progn
222 (defun ,name (arg)
223 ,doc
224 (interactive "p")
225 (let ((x (intern (format "transpose-%s" ,scope))))
226 (if (use-region-p)
227 (funcall x 0)
228 (funcall x arg))))
229 ,(when key
230 `(define-key global-map (kbd ,key) #',name))))
232 (op/deftranspose op/transpose-lines "lines" "C-x C-t"
233 "Transpose lines or swap over active region.")
235 (op/deftranspose op/transpose-paragraphs "paragraphs" "C-S-t"
236 "Transpose paragraph or swap over active region.")
238 (op/deftranspose op/transpose-sentences "sentences" "C-x M-t"
239 "Transpose sentences or swap over active region.")
241 (op/deftranspose op/transpose-sexps "sexps" "C-M-t"
242 "Transpose sexps or swap over active region.")
244 (op/deftranspose op/transpose-words "words" "M-t"
245 "Transpose words or swap over active region.")
247 (defun op/narrow-or-widen-dwim (p)
248 "Widen if the buffer is narrowed, narrow-dwim otherwise.
249 Dwim means: region, org-src-block, org-subtree or defun,
250 whichever applies first. Narrowing to org-src-blocks actually
251 calls `org-edit-src-code'.
253 With prefix P, don't widen, just narrow even if buffer is already
254 narrowed. With P being -, narrow to page instead of to defun.
256 Taken from endless parentheses."
257 (interactive "P")
258 (declare (interactive-only))
259 (cond ((and (buffer-narrowed-p) (not p)) (widen))
260 ((region-active-p)
261 (narrow-to-region (region-beginning)
262 (region-end)))
263 ((derived-mode-p 'org-mode)
264 ;; `org-edit-src-code' isn't a real narrowing
265 (cond ((ignore-errors (org-edit-src-code) t))
266 ((ignore-errors (org-narrow-to-block) t))
267 (t (org-narrow-to-subtree))))
268 ((eql p '-) (narrow-to-page))
269 (t (narrow-to-defun))))
271 (define-key global-map (kbd "C-c w") #'op/narrow-or-widen-dwim)
273 (with-eval-after-load 'dired
274 (add-hook 'dired-mode-hook #'dired-hide-details-mode)
275 (add-hook 'dired-mode-hook #'dired-omit-mode)
277 (define-key dired-mode-map (kbd "C-c w") #'wdired-change-to-wdired-mode)
279 (require 'dired-x)
280 (setq dired-listing-switches "-lahF"
281 dired-dwim-target t
282 dired-deletion-confirmer #'y-or-n-p
283 dired-do-revert-buffer t))
285 ;; just like telescope!
286 (with-eval-after-load 'diff-mode
287 (define-key diff-mode-map (kbd "M-SPC") #'scroll-down-command))
289 (with-eval-after-load 'elisp-mode
290 (add-hook 'emacs-lisp-mode-hook #'checkdoc-minor-mode)
291 (add-hook 'emacs-lisp-mode-hook #'prettify-symbols-mode)
292 (let ((map emacs-lisp-mode-map))
293 (define-key map (kbd "C-c C-k") #'eval-buffer)
294 (define-key map (kbd "C-c k") #'op/ert-all)
295 (define-key map (kbd "C-c C-z") #'op/ielm-repl)))
297 (with-eval-after-load 'help
298 (add-hook 'help-mode-hook #'visual-line-mode))
300 ;; add melpa
301 (add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t)
303 ;; packages that i want to be installed
304 (dolist (pkg '(vc-got eglot sly cider go-mode web-mode lua-mode
305 markdown-mode yaml-mode gemini-mode
306 form-feed shackle puni orderless))
307 (unless (package-installed-p pkg)
308 (message "Installing %s" pkg)
309 (package-install pkg)))
311 (global-form-feed-mode +1)
313 (add-hook 'text-mode-hook #'puni-mode)
314 (add-hook 'prog-mode-hook #'puni-mode)
315 (define-key puni-mode-map (kbd "C-)") #'puni-slurp-forward)
316 (define-key puni-mode-map (kbd "C-(") #'puni-barf-forward)
318 ;;(setq completion-styles '(basic substring initials flex partial-completion))
319 (setq completion-styles '(orderless basic)
320 completion-category-overrides '((file (styles basic partial-completion))))
322 (setq completions-detailed t)
324 (with-eval-after-load 'cider
325 (define-key cider-repl-mode-map (kbd "C-c M-o") #'cider-repl-clear-buffer))
327 (with-eval-after-load 'go-mode
328 (add-hook 'go-mode-hook #'subword-mode))
330 (with-eval-after-load 'tcl
331 (setq-default tcl-indent-level 8))
333 (with-eval-after-load 'eglot
334 (define-key eglot-mode-map (kbd "<f1>") #'eglot-code-actions)
335 (define-key eglot-mode-map (kbd "<f2>") #'eglot-format)
336 (add-to-list 'eglot-ignored-server-capabilites
337 :documentHighlightProvider)
338 (add-to-list 'eglot-server-programs
339 '(c-mode . ("clangd" "--header-insertion=never"))))
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 (setq web-mode-enable-auto-pairing nil))
357 (with-eval-after-load 'css-mode
358 (add-hook 'css-mode-hook #'op/disable-tabs))
360 (with-eval-after-load 'flymake
361 (define-key prog-mode-map (kbd "C-c ! n") #'flymake-goto-next-error)
362 (define-key prog-mode-map (kbd "C-c ! p") #'flymake-goto-prev-error))
364 (with-eval-after-load 'cc-mode
365 (setq c-basic-offset 8
366 c-default-style "K&R")
367 (dolist (hook '(c-mode-hook c++-mode-hook))
368 (add-hook hook #'abbrev-mode)
369 (add-hook hook #'subword-mode))
370 (defun op/c-indent ()
371 (interactive)
372 (c-set-offset 'arglist-intro '+)
373 (c-set-offset 'arglist-cont-nonempty '*)
374 (c-set-offset 'label 1))
375 (add-hook 'c-mode-hook #'op/c-indent)
376 ;; TODO: improve it!
377 (defun op/c-add-include (path &optional localp)
378 "Include PATH at the start of the file.
379 If LOCALP is non-nil, the include will be \"local\"."
380 (interactive "Mheader to include: \nP")
381 (save-excursion
382 (let ((re (if localp
383 "^#[ \t]*include[ \t]*\""
384 "^#[ \t]*include[ \t]*<"))
385 (ignore-re "^#include \"compat.h\"")
386 start)
387 (goto-char (point-min))
388 (while (not (or (and (looking-at re)
389 (not (looking-at ignore-re)))
390 (eobp)))
391 (forward-line))
392 (when (eobp)
393 (error "Don't know where to insert the header"))
394 (open-line 1)
395 (insert "#include " (if localp "\"\"" "<>"))
396 (backward-char)
397 (insert path)
398 (move-beginning-of-line 1)
399 (setq start (point))
400 (forward-line)
401 (while (and (looking-at re)
402 (not (eobp)))
403 (forward-line))
404 (sort-lines nil start (point)))))
405 (define-key c-mode-map (kbd "C-c C-a") #'op/c-add-include))
407 (with-eval-after-load 'perl-mode
408 (setq perl-indent-level 8))
410 (with-eval-after-load 'sh-script
411 (setq sh-basic-offset 8
412 sh-indent-after-loop-construct 8
413 sh-indent-after-continuation nil))
417 (setq eshell-hist-ignoredups t)
419 (defun op/eshell-bufname (dir)
420 (concat "*eshell " (expand-file-name dir) "*"))
422 (defun op/eshell (arg)
423 "Run or jump to eshell in current project.
424 If called with prefix argument ARG always create a new eshell
425 buffer."
426 (interactive "P")
427 (let* ((proj (project-current))
428 (dir (if (and proj (not arg))
429 (project-root proj)
430 default-directory))
431 (default-directory dir)
432 (eshell-buffer-name (let ((name (op/eshell-bufname dir)))
433 (if arg
434 (generate-new-buffer name)
435 name))))
436 (eshell)))
437 (define-key global-map (kbd "C-c e") #'op/eshell)
439 (with-eval-after-load 'eshell
440 (setq eshell-save-history-on-exit t
441 eshell-history-size 1024
443 eshell-compl-dir-ignore
444 "\\`\\(\\.\\.?\\|CVS\\|\\.svn\\|\\.git\\|\\.got\\)/\\'")
446 (defun op/eshell-after-cd (&rest _)
447 (rename-buffer (op/eshell-bufname default-directory) t))
449 (advice-add #'eshell/cd :after #'op/eshell-after-cd))
451 (with-eval-after-load 'esh-mode
452 (defun op/clear-eshell ()
453 (interactive "")
454 (let ((inhibit-read-only t))
455 (erase-buffer)
456 (eshell-send-input)))
458 (define-key eshell-command-map (kbd "M-o") #'op/clear-eshell))
461 ;; sndio.el
462 (unless (package-installed-p 'sndio)
463 (package-install-file "~/w/sndio.el/sndio.el"))
466 ;; saturn
467 (unless (package-installed-p 'saturn)
468 (package-install-file "~/w/saturn/GUI/saturn.el"))
471 ;; emacs-pq
472 (add-to-list 'load-path "~/build/emacs-libpq/")
473 (unless (package-installed-p 'pq)
474 (package-install-file "~/build/emacs-libpq/pq.el"))
477 ;; plass
478 (unless (package-installed-p 'plass)
479 (ignore-errors
480 (package-install-file "~/w/plass/extra/plass.el")))
482 (with-eval-after-load 'plass
483 (setq plass-filter "!2fa"
484 plass-totp-filter "2fa"))
488 (setq shackle-default-rule nil
489 shackle-rules
490 (let ((repls "\\*\\(cider-repl\\|sly-mrepl\\|ielm\\)")
491 (godot "\\*godot - .*\\*")
492 (vcs "\\*\\(Flymake\\|Package-Lint\\|vc-\\(git\\|got\\) :\\).*")
493 (elfeed "\\*elfeed-entry\\*")
494 (vmd "\\*vmd console .*"))
495 `(("*Async Shell Command*" :ignore t)
496 (,repls :regexp t
497 :align below
498 :size 0.3)
499 (,godot :regexp t
500 :align t
501 :size 0.3)
502 (occur-mode :select t
503 :align right
504 :size 0.3)
505 (diff-mode :select t)
506 (help-mode :select t
507 :align left
508 :size 0.3)
509 (,vcs :regexp t
510 :align above
511 :size 0.15
512 :select t)
513 (,elfeed :regexp t
514 :align t
515 :select t
516 :size 0.75)
517 (,vmd :regexp t
518 :align below
519 :select t
520 :size 0.3))))
521 (shackle-mode +1)
523 ;; (setq display-buffer-alist nil)