1 ;; get rid of custom from my init file
2 (setq custom-file "~/.emacs.d/emacs-custom.el")
5 (setq-default abbrev-mode t)
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
17 require-final-newline t
21 enable-recursive-minibuffers 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 ;; I don't like how compile uses `make -k' by default, I want to stop
35 ;; on errors / warnings.
36 (setq compile-command "make")
38 ;; "diff refinement", i.e. highlighting the changes in a more granular
39 ;; way, is quite awful to have it enabled by default. sometimes is
40 ;; useful, but for me it's more of a visual noise most of the times.
41 (setq diff-refine nil)
43 ;; disable also the syntax highlighting in the diff buffers
44 (setq diff-font-lock-syntax nil)
46 (define-key global-map (kbd "C-x C-b") #'ibuffer)
47 (define-key global-map (kbd "M-g i") #'imenu)
50 "Just like `imenu', but always flattened!"
54 (define-key minibuffer-mode-map (kbd "C-w") #'backward-kill-word)
56 ;; niceties for the standard completion
57 (setq 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 "M-RET")
73 #'minibuffer-choose-completion)
75 (defun op/reverse-other-window ()
76 "Like `other-window', but reverse."
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)
94 (setq whitespace-style '(face trailing)
95 backward-delete-char-untabify-method 'hungry
96 tab-always-indent 'complete
98 sentence-end-double-space t)
99 (setq-default indent-tabs-mode t)
101 (defun op/enable-tabs ()
102 "Enable `indent-tabs-mode' in the current buffer."
104 (setq-local indent-tabs-mode t))
106 (defun op/disable-tabs ()
107 "Disable `indent-tabs-mode' in the current buffer."
109 (setq-local indent-tabs-mode nil))
111 (add-hook 'conf-mode-hook #'op/enable-tabs)
112 (add-hook 'text-mode-hook #'op/enable-tabs)
113 (add-hook 'prog-mode-hook #'op/enable-tabs)
114 (add-hook 'prog-mode-hook #'whitespace-mode)
115 (add-hook 'text-mode-hook #'whitespace-mode)
117 (dolist (hook '(emacs-lisp-mode-hook
119 clojurescript-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)
138 ;; "-misc-fixed-medium-r-semicondensed--13-120-75-75-c-60-iso10646-1"
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")
151 (setq history-delete-duplicates t
153 savehist-save-minibuffer-history t)
154 (electric-pair-mode +1)
156 (when (boundp #'electric-quote-mode)
157 (electric-quote-mode +1)
158 (setq electric-quote-comment nil))
160 (define-key global-map (kbd "M-/") #'hippie-expand)
161 (setq hippie-expand-try-functions-list
163 try-expand-dabbrev-all-buffers
164 try-expand-dabbrev-from-kill
165 try-complete-file-name-partially
166 try-complete-file-name
167 try-expand-all-abbrevs
170 try-complete-lisp-symbol-partially
171 try-complete-lisp-symbol))
173 (setq isearch-lazy-count t
174 search-whitespace-regexp ".*?"
175 isearch-allow-scroll 'unlimited)
177 (defun op/buffer-to-side-window (place)
178 "Place the current buffer in the side window at PLACE."
179 (interactive (list (intern
180 (completing-read "Which side: "
181 '(top left right bottom)))))
182 (let ((buf (current-buffer)))
183 (display-buffer-in-side-window
184 buf `((window-height . 0.15)
187 (window-parameters . ((no-delete-other-windows . t)))))
190 (defun op/visit-new-migration-file (name)
191 "Visit a new SQL migration file named after NAME."
192 (interactive "Mname: ")
193 (let* ((name (replace-regexp-in-string " " "-" (string-trim name)))
194 (f (format "%s-%s.sql"
195 (format-time-string "%Y%m%d%H%M")
199 (defun op/fill-or-unfill (fn &optional justify region)
200 "Meant to be an adviced :around `fill-paragraph'.
201 FN is the original `fill-column'. If `last-command' is
202 `fill-paragraph', unfill it, fill it otherwise. Inspired from a
203 post on endless parentheses. Optional argument JUSTIFY and
204 REGION are passed to `fill-paragraph'."
206 (if (eq last-command 'fill-paragraph)
207 (progn (setq this-command nil)
210 (funcall fn justify region)))
211 (advice-add 'fill-paragraph :around #'op/fill-or-unfill)
213 (defmacro op/deftranspose (name scope key doc)
214 "Macro to produce transposition functions.
215 NAME is the function's symbol. SCOPE is the text object to
216 operate on. Optional DOC is the function's docstring.
218 Transposition over an active region will swap the object at
219 mark (region beginning) with the one at point (region end).
221 It can optionally define a key for the defined function in the
222 `global-map' if KEY is passed.
224 Originally from protesilaos' dotemacs."
225 (declare (indent defun))
230 (let ((x (intern (format "transpose-%s" ,scope))))
235 `(define-key global-map (kbd ,key) #',name))))
237 (op/deftranspose op/transpose-lines "lines" "C-x C-t"
238 "Transpose lines or swap over active region.")
240 (op/deftranspose op/transpose-paragraphs "paragraphs" "C-S-t"
241 "Transpose paragraph or swap over active region.")
243 (op/deftranspose op/transpose-sentences "sentences" "C-x M-t"
244 "Transpose sentences or swap over active region.")
246 (op/deftranspose op/transpose-sexps "sexps" "C-M-t"
247 "Transpose sexps or swap over active region.")
249 (op/deftranspose op/transpose-words "words" "M-t"
250 "Transpose words or swap over active region.")
252 (defun op/narrow-or-widen-dwim (p)
253 "Widen if the buffer is narrowed, narrow-dwim otherwise.
254 Dwim means: region, org-src-block, org-subtree or defun,
255 whichever applies first. Narrowing to org-src-blocks actually
256 calls `org-edit-src-code'.
258 With prefix P, don't widen, just narrow even if buffer is already
259 narrowed. With P being -, narrow to page instead of to defun.
261 Taken from endless parentheses."
263 (declare (interactive-only))
264 (cond ((and (buffer-narrowed-p) (not p)) (widen))
266 (narrow-to-region (region-beginning)
268 ((derived-mode-p 'org-mode)
269 ;; `org-edit-src-code' isn't a real narrowing
270 (cond ((ignore-errors (org-edit-src-code) t))
271 ((ignore-errors (org-narrow-to-block) t))
272 (t (org-narrow-to-subtree))))
273 ((eql p '-) (narrow-to-page))
274 (t (narrow-to-defun))))
276 (define-key global-map (kbd "C-c w") #'op/narrow-or-widen-dwim)
278 (with-eval-after-load 'dired
279 (add-hook 'dired-mode-hook #'dired-hide-details-mode)
280 (add-hook 'dired-mode-hook #'dired-omit-mode)
282 (define-key dired-mode-map (kbd "C-c w") #'wdired-change-to-wdired-mode)
285 (setq dired-listing-switches "-lahF"
287 dired-deletion-confirmer #'y-or-n-p
288 dired-do-revert-buffer t))
290 ;; just like telescope!
291 (with-eval-after-load 'diff-mode
292 (define-key diff-mode-map (kbd "M-SPC") #'scroll-down-command))
294 (with-eval-after-load 'elisp-mode
295 (add-hook 'emacs-lisp-mode-hook #'checkdoc-minor-mode)
296 (add-hook 'emacs-lisp-mode-hook #'prettify-symbols-mode)
297 (let ((map emacs-lisp-mode-map))
298 (define-key map (kbd "C-c C-k") #'eval-buffer)
299 (define-key map (kbd "C-c k") #'op/ert-all)
300 (define-key map (kbd "C-c C-z") #'op/ielm-repl)))
302 (with-eval-after-load 'help
303 (add-hook 'help-mode-hook #'visual-line-mode))
306 (add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t)
308 ;; packages that i want to be installed
309 (dolist (pkg '(vc-got eglot sly cider go-mode web-mode lua-mode
310 markdown-mode yaml-mode gemini-mode
311 form-feed shackle puni orderless))
312 (unless (package-installed-p pkg)
313 (message "Installing %s" pkg)
314 (package-install pkg)))
316 (global-form-feed-mode +1)
318 (add-hook 'text-mode-hook #'puni-mode)
319 (add-hook 'prog-mode-hook #'puni-mode)
320 (define-key puni-mode-map (kbd "C-)") #'puni-slurp-forward)
321 (define-key puni-mode-map (kbd "C-(") #'puni-barf-forward)
323 ;;(setq completion-styles '(basic substring initials flex partial-completion))
324 (setq completion-styles '(orderless basic)
325 completion-category-overrides '((file (styles basic partial-completion))))
327 (setq completions-detailed t)
329 (with-eval-after-load 'cider
330 (define-key cider-repl-mode-map (kbd "C-c M-o") #'cider-repl-clear-buffer))
332 (with-eval-after-load 'go-mode
333 (add-hook 'go-mode-hook #'subword-mode))
335 (with-eval-after-load 'eglot
336 (define-key eglot-mode-map (kbd "<f1>") #'eglot-code-actions)
337 (define-key eglot-mode-map (kbd "<f2>") #'eglot-format)
338 (add-to-list 'eglot-ignored-server-capabilites
339 :documentHighlightProvider)
340 (add-to-list 'eglot-server-programs
341 '(c-mode . ("clangd" "--header-insertion=never"))))
343 (add-hook 'emacs-lisp-mode #'nameless-mode)
344 (with-eval-after-load 'nameless
345 (setq nameless-private-prefix t
346 nameless-affect-indentation-and-filling nil)
347 (define-key emacs-lisp-mode-map (kbd "_") #'nameless-insert-name-or-self-insert))
349 (add-to-list 'auto-mode-alist '("\\.html\\'" . web-mode))
350 (with-eval-after-load 'web-mode
351 (setq web-mode-markup-indent-offset 2
352 web-mode-css-indent-offset 2
353 web-mode-style-padding 0
354 web-mode-enable-engine-detection t)
355 (add-hook 'web-mode-hook #'op/disable-tabs)
357 ;; fix .dir-locals.el
358 (defun op/web-mode-fix-dir-locals ()
359 (when (derived-mode-p major-mode 'web-mode)
360 (web-mode-guess-engine-and-content-type)))
361 (add-hook 'hack-local-variables-hook #'op/web-mode-fix-dir-locals)
363 (setq web-mode-enable-auto-pairing nil))
365 (with-eval-after-load 'css-mode
366 (add-hook 'css-mode-hook #'op/disable-tabs))
368 (with-eval-after-load 'flymake
369 (define-key prog-mode-map (kbd "C-c ! n") #'flymake-goto-next-error)
370 (define-key prog-mode-map (kbd "C-c ! p") #'flymake-goto-prev-error))
372 (with-eval-after-load 'cc-mode
373 (setq c-basic-offset 8
374 c-default-style "K&R")
375 (dolist (hook '(c-mode-hook c++-mode-hook))
376 (add-hook hook #'abbrev-mode)
377 (add-hook hook #'subword-mode))
378 (defun op/c-indent ()
380 (c-set-offset 'arglist-intro '+)
381 (c-set-offset 'arglist-cont-nonempty '*)
382 (c-set-offset 'label 1))
383 (add-hook 'c-mode-hook #'op/c-indent)
385 (defun op/c-add-include (path &optional localp)
386 "Include PATH at the start of the file.
387 If LOCALP is non-nil, the include will be \"local\"."
388 (interactive "Mheader to include: \nP")
391 "^#[ \t]*include[ \t]*\""
392 "^#[ \t]*include[ \t]*<"))
393 (ignore-re "^#include \"compat.h\"")
395 (goto-char (point-min))
396 (while (not (or (and (looking-at re)
397 (not (looking-at ignore-re)))
401 (error "Don't know where to insert the header"))
403 (insert "#include " (if localp "\"\"" "<>"))
406 (move-beginning-of-line 1)
409 (while (and (looking-at re)
412 (sort-lines nil start (point)))))
413 (define-key c-mode-map (kbd "C-c C-a") #'op/c-add-include))
415 (with-eval-after-load 'perl-mode
416 (setq perl-indent-level 8))
418 (with-eval-after-load 'sh-script
419 (setq sh-basic-offset 8
420 sh-indent-after-loop-construct 8
421 sh-indent-after-continuation nil))
425 (setq eshell-hist-ignoredups t)
427 (defun op/eshell-bufname (dir)
428 (concat "*eshell " (expand-file-name dir) "*"))
430 (defun op/eshell (arg)
431 "Run or jump to eshell in current project.
432 If called with prefix argument ARG always create a new eshell
435 (let* ((proj (project-current))
436 (dir (if (and proj (not arg))
439 (default-directory dir)
440 (eshell-buffer-name (let ((name (op/eshell-bufname dir)))
442 (generate-new-buffer name)
445 (define-key global-map (kbd "C-c e") #'op/eshell)
447 (with-eval-after-load 'eshell
448 (setq eshell-save-history-on-exit t
449 eshell-history-size 1024
451 eshell-compl-dir-ignore
452 "\\`\\(\\.\\.?\\|CVS\\|\\.svn\\|\\.git\\|\\.got\\)/\\'")
454 (defun op/eshell-after-cd (&rest _)
455 (rename-buffer (op/eshell-bufname default-directory) t))
457 (advice-add #'eshell/cd :after #'op/eshell-after-cd))
459 (with-eval-after-load 'esh-mode
460 (defun op/clear-eshell ()
462 (let ((inhibit-read-only t))
464 (eshell-send-input)))
466 (define-key eshell-command-map (kbd "M-o") #'op/clear-eshell))
470 (unless (package-installed-p 'sndio)
471 (package-install-file "~/w/sndio.el/sndio.el"))
475 (unless (package-installed-p 'saturn)
476 (package-install-file "~/w/saturn/GUI/saturn.el"))
480 (add-to-list 'load-path "~/build/emacs-libpq/")
481 (unless (package-installed-p 'pq)
482 (package-install-file "~/build/emacs-libpq/pq.el"))
486 (unless (package-installed-p 'plass)
488 (package-install-file "~/w/plass/plass.el")))
490 (with-eval-after-load 'plass
491 (setq plass-filter "!2fa"
492 plass-totp-filter "2fa"))
496 (setq shackle-default-rule nil
498 (let ((repls "\\*\\(cider-repl\\|sly-mrepl\\|ielm\\)")
499 (godot "\\*godot - .*\\*")
500 (vcs "\\*\\(Flymake\\|Package-Lint\\|vc-\\(git\\|got\\) :\\).*")
501 (elfeed "\\*elfeed-entry\\*")
502 (vmd "\\*vmd console .*"))
503 `(("*Async Shell Command*" :ignore t)
510 (occur-mode :select t
513 (diff-mode :select t)
531 ;; (setq display-buffer-alist nil)