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 ;; 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)
49 (defun op/imenu ()
50 "Just like `imenu', but always flattened!"
51 (interactive ))
53 ;; mg-like
54 (define-key minibuffer-mode-map (kbd "C-w") #'backward-kill-word)
56 (defun op/reverse-other-window ()
57 "Like `other-window', but reverse."
58 (interactive "")
59 (other-window -1))
60 (define-key global-map (kbd "C-x O") #'op/reverse-other-window)
62 (define-key global-map (kbd "C-x v f") #'vc-pull)
64 (setq uniquify-buffer-name-style 'forward
65 uniquify-strip-common-suffix t)
67 (setq-default scroll-up-aggressively 0.0
68 scroll-down-aggressively 0.0
69 scroll-preserve-screen-position t
70 next-screen-context-lines 1)
72 (define-key global-map (kbd "M-z") #'zap-up-to-char)
74 (require 'whitespace)
75 (setq whitespace-style '(face trailing)
76 backward-delete-char-untabify-method 'hungry
77 tab-always-indent 'complete
78 tab-width 8
79 sentence-end-double-space t)
80 (setq-default indent-tabs-mode t)
82 (defun op/enable-tabs ()
83 "Enable `indent-tabs-mode' in the current buffer."
84 (interactive)
85 (setq-local indent-tabs-mode t))
87 (defun op/disable-tabs ()
88 "Disable `indent-tabs-mode' in the current buffer."
89 (interactive)
90 (setq-local indent-tabs-mode nil))
92 (add-hook 'conf-mode-hook #'op/enable-tabs)
93 (add-hook 'text-mode-hook #'op/enable-tabs)
94 (add-hook 'prog-mode-hook #'op/enable-tabs)
95 (add-hook 'prog-mode-hook #'whitespace-mode)
96 (add-hook 'text-mode-hook #'whitespace-mode)
98 (dolist (hook '(emacs-lisp-mode-hook
99 clojure-mode-hook
100 clojurescript-mode-hook
101 clojurec-mode-hook
102 scss-mode-hook))
103 (add-hook hook #'op/disable-tabs))
105 (with-eval-after-load 'log-edit
106 (add-hook 'log-edit-mode #'auto-fill-mode))
108 ;; free the c-z binding
109 (define-key global-map (kbd "C-z") nil)
110 (define-key global-map (kbd "C-z V") #'variable-pitch-mode)
111 (define-key global-map (kbd "C-z n") #'display-line-numbers-mode)
113 (define-key global-map (kbd "M-SPC") #'cycle-spacing)
114 (define-key global-map (kbd "M-u") #'upcase-dwim)
115 (define-key global-map (kbd "M-l") #'downcase-dwim)
116 (define-key global-map (kbd "M-c") #'capitalize-dwim)
118 (let ((font "-misc-fixed-medium-r-semicondensed--13-120-75-75-c-60-iso10646-1"))
119 (set-frame-font font nil t)
120 (add-to-list 'default-frame-alist `(font . ,font)))
122 ;; fix the emojis too
123 (set-fontset-font t 'emoji '("Noto Emoji" . "iso10646-1")
124 nil 'prepend)
126 ;; some cool stuff
127 (save-place-mode +1)
128 (savehist-mode +1)
129 (setq history-delete-duplicates t
130 history-length 1000
131 savehist-save-minibuffer-history t)
132 (electric-pair-mode +1)
134 (when (boundp #'electric-quote-mode)
135 (electric-quote-mode +1)
136 (setq electric-quote-comment nil))
138 (define-key global-map (kbd "M-/") #'hippie-expand)
139 (setq hippie-expand-try-functions-list
140 '(try-expand-dabbrev
141 try-expand-dabbrev-all-buffers
142 try-expand-dabbrev-from-kill
143 try-complete-file-name-partially
144 try-complete-file-name
145 try-expand-all-abbrevs
146 try-expand-list
147 try-expand-line
148 try-complete-lisp-symbol-partially
149 try-complete-lisp-symbol))
151 (setq isearch-lazy-count t
152 search-whitespace-regexp ".*?"
153 isearch-allow-scroll 'unlimited)
155 (defun op/buffer-to-side-window (place)
156 "Place the current buffer in the side window at PLACE."
157 (interactive (list (intern
158 (completing-read "Which side: "
159 '(top left right bottom)))))
160 (let ((buf (current-buffer)))
161 (display-buffer-in-side-window
162 buf `((window-height . 0.15)
163 (side . ,place)
164 (slot . -1)
165 (window-parameters . ((no-delete-other-windows . t)))))
166 (delete-window)))
168 (defun op/visit-new-migration-file (name)
169 "Visit a new SQL migration file named after NAME."
170 (interactive "Mname: ")
171 (let* ((name (replace-regexp-in-string " " "-" (string-trim name)))
172 (f (format "%s-%s.sql"
173 (format-time-string "%Y%m%d%H%M")
174 name)))
175 (find-file f)))
177 (defun op/fill-or-unfill (fn &optional justify region)
178 "Meant to be an adviced :around `fill-paragraph'.
179 FN is the original `fill-column'. If `last-command' is
180 `fill-paragraph', unfill it, fill it otherwise. Inspired from a
181 post on endless parentheses. Optional argument JUSTIFY and
182 REGION are passed to `fill-paragraph'."
183 (let ((fill-column
184 (if (eq last-command 'fill-paragraph)
185 (progn (setq this-command nil)
186 (point-max))
187 fill-column)))
188 (funcall fn justify region)))
189 (advice-add 'fill-paragraph :around #'op/fill-or-unfill)
191 (defmacro op/deftranspose (name scope key doc)
192 "Macro to produce transposition functions.
193 NAME is the function's symbol. SCOPE is the text object to
194 operate on. Optional DOC is the function's docstring.
196 Transposition over an active region will swap the object at
197 mark (region beginning) with the one at point (region end).
199 It can optionally define a key for the defined function in the
200 `global-map' if KEY is passed.
202 Originally from protesilaos' dotemacs."
203 (declare (indent defun))
204 `(progn
205 (defun ,name (arg)
206 ,doc
207 (interactive "p")
208 (let ((x (intern (format "transpose-%s" ,scope))))
209 (if (use-region-p)
210 (funcall x 0)
211 (funcall x arg))))
212 ,(when key
213 `(define-key global-map (kbd ,key) #',name))))
215 (op/deftranspose op/transpose-lines "lines" "C-x C-t"
216 "Transpose lines or swap over active region.")
218 (op/deftranspose op/transpose-paragraphs "paragraphs" "C-S-t"
219 "Transpose paragraph or swap over active region.")
221 (op/deftranspose op/transpose-sentences "sentences" "C-x M-t"
222 "Transpose sentences or swap over active region.")
224 (op/deftranspose op/transpose-sexps "sexps" "C-M-t"
225 "Transpose sexps or swap over active region.")
227 (op/deftranspose op/transpose-words "words" "M-t"
228 "Transpose words or swap over active region.")
230 (defun op/narrow-or-widen-dwim (p)
231 "Widen if the buffer is narrowed, narrow-dwim otherwise.
232 Dwim means: region, org-src-block, org-subtree or defun,
233 whichever applies first. Narrowing to org-src-blocks actually
234 calls `org-edit-src-code'.
236 With prefix P, don't widen, just narrow even if buffer is already
237 narrowed. With P being -, narrow to page instead of to defun.
239 Taken from endless parentheses."
240 (interactive "P")
241 (declare (interactive-only))
242 (cond ((and (buffer-narrowed-p) (not p)) (widen))
243 ((region-active-p)
244 (narrow-to-region (region-beginning)
245 (region-end)))
246 ((derived-mode-p 'org-mode)
247 ;; `org-edit-src-code' isn't a real narrowing
248 (cond ((ignore-errors (org-edit-src-code) t))
249 ((ignore-errors (org-narrow-to-block) t))
250 (t (org-narrow-to-subtree))))
251 ((eql p '-) (narrow-to-page))
252 (t (narrow-to-defun))))
254 (define-key global-map (kbd "C-c w") #'op/narrow-or-widen-dwim)
256 (with-eval-after-load 'dired
257 (add-hook 'dired-mode-hook #'dired-hide-details-mode)
258 (add-hook 'dired-mode-hook #'dired-omit-mode)
260 (define-key dired-mode-map (kbd "C-c w") #'wdired-change-to-wdired-mode)
262 (require 'dired-x)
263 (setq dired-listing-switches "-lahF"
264 dired-dwim-target t
265 dired-deletion-confirmer #'y-or-n-p
266 dired-do-revert-buffer t))
268 ;; just like telescope!
269 (with-eval-after-load 'diff-mode
270 (define-key diff-mode-map (kbd "M-SPC") #'scroll-down-command))
272 (with-eval-after-load 'elisp-mode
273 (add-hook 'emacs-lisp-mode-hook #'checkdoc-minor-mode)
274 (add-hook 'emacs-lisp-mode-hook #'prettify-symbols-mode)
275 (let ((map emacs-lisp-mode-map))
276 (define-key map (kbd "C-c C-k") #'eval-buffer)
277 (define-key map (kbd "C-c k") #'op/ert-all)
278 (define-key map (kbd "C-c C-z") #'op/ielm-repl)))
280 (with-eval-after-load 'help
281 (add-hook 'help-mode-hook #'visual-line-mode))
283 ;; add melpa
284 (add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t)
286 ;; packages that i want to be installed
287 (dolist (pkg '(vc-got pdf-tools eglot nameless sly cider go-mode web-mode
288 lua-mode markdown-mode yaml-mode gemini-mode elfeed
289 form-feed shackle embark consult mct puni))
290 (unless (package-installed-p pkg)
291 (message "Installing %s" pkg)
292 (package-install pkg)))
294 (global-form-feed-mode +1)
296 (add-hook 'text-mode-hook #'puni-mode)
297 (add-hook 'prog-mode-hook #'puni-mode)
298 (define-key puni-mode-map (kbd "C-)") #'puni-slurp-forward)
299 (define-key puni-mode-map (kbd "C-(") #'puni-barf-forward)
301 (setq completion-styles '(basic substring initials flex partial-completion))
303 (require 'consult) ;; some stuff lacks an autoload and i don't want to debug it
305 (cl-loop for (key . func) in '(("C-x :" . consult-complex-command)
306 ("C-x b" . consult-buffer)
307 ("C-x 4 b" . consult-buffer-other-window)
308 ("C-x 5 b" . consult-buffer-other-frame)
309 ("C-x r b" . consult-bookmark)
310 ("C-x p b" . consult-project-buffer)
311 ("M-y" . consult-yank-pop)
312 ("M-g g" . consult-goto-line)
313 ("M-g M-g" . consult-goto-line)
314 ("M-g m" . consult-mark)
315 ("M-g i" . consult-imenu)
316 ("M-s l" . consult-line)
317 ("M-s L" . consult-line-multi)
318 ("M-s m" . consult-multi-occur))
319 do (define-key global-map (kbd key) func))
320 (add-hook 'completion-list-mode-hook #'consult-preview-at-point-mode)
322 (setq completions-detailed t)
323 (mct-minibuffer-mode +1)
324 (mct-region-mode +1)
326 ;; override the binding for the annoying mct-backward-updir.
327 (define-key mct-minibuffer-local-filename-completion-map
328 (kbd "DEL") #'backward-delete-char)
330 (setq mct-remove-shadowed-file-names t
331 mct-completions-format 'one-column
332 mct-completion-passlist '(Info-goto-node
333 Info-index
334 Info-menu
335 vc-retrieve-tag
336 imenu
337 file
338 buffer
339 consult-project-buffer
340 kill-ring
341 consult-buffer))
343 (with-eval-after-load 'cider
344 (define-key cider-repl-mode-map (kbd "C-c M-o") #'cider-repl-clear-buffer))
346 (with-eval-after-load 'go-mode
347 (add-hook 'go-mode-hook #'subword-mode))
349 (with-eval-after-load 'eglot
350 (define-key eglot-mode-map (kbd "<f1>") #'eglot-code-actions)
351 (define-key eglot-mode-map (kbd "<f2>") #'eglot-format)
352 (add-to-list 'eglot-ignored-server-capabilites
353 :documentHighlightProvider)
354 (add-to-list 'eglot-server-programs
355 '(c-mode . ("clangd" "--header-insertion=never"))))
357 (add-hook 'emacs-lisp-mode #'nameless-mode)
358 (with-eval-after-load 'nameless
359 (setq nameless-private-prefix t
360 nameless-affect-indentation-and-filling nil)
361 (define-key emacs-lisp-mode-map (kbd "_") #'nameless-insert-name-or-self-insert))
363 (add-to-list 'auto-mode-alist '("\\.html\\'" . web-mode))
364 (with-eval-after-load 'web-mode
365 (setq web-mode-markup-indent-offset 2
366 web-mode-css-indent-offset 2
367 web-mode-style-padding 0
368 web-mode-enable-engine-detection t)
369 (add-hook 'web-mode-hook #'op/disable-tabs)
371 ;; fix .dir-locals.el
372 (defun op/web-mode-fix-dir-locals ()
373 (when (derived-mode-p major-mode 'web-mode)
374 (web-mode-guess-engine-and-content-type)))
375 (add-hook 'hack-local-variables-hook #'op/web-mode-fix-dir-locals)
377 (setq web-mode-enable-auto-pairing nil))
379 (with-eval-after-load 'css-mode
380 (add-hook 'css-mode-hook #'op/disable-tabs))
382 (with-eval-after-load 'flymake
383 (define-key prog-mode-map (kbd "C-c ! n") #'flymake-goto-next-error)
384 (define-key prog-mode-map (kbd "C-c ! p") #'flymake-goto-prev-error))
386 (with-eval-after-load 'cc-mode
387 (setq c-basic-offset 8
388 c-default-style "K&R")
389 (dolist (hook '(c-mode-hook c++-mode-hook))
390 (add-hook hook #'abbrev-mode)
391 (add-hook hook #'subword-mode))
392 (defun op/c-indent ()
393 (interactive)
394 (c-set-offset 'arglist-intro '+)
395 (c-set-offset 'arglist-cont-nonempty '*))
396 (add-hook 'c-mode-hook #'op/c-indent)
397 ;; TODO: improve it!
398 (defun op/c-add-include (path &optional localp)
399 "Include PATH at the start of the file.
400 If LOCALP is non-nil, the include will be \"local\"."
401 (interactive "Mheader to include: \nP")
402 (save-excursion
403 (let ((re (if localp
404 "^#[ \t]*include[ \t]*\""
405 "^#[ \t]*include[ \t]*<"))
406 (ignore-re "^#include \"compat.h\"")
407 start)
408 (goto-char (point-min))
409 (while (not (or (and (looking-at re)
410 (not (looking-at ignore-re)))
411 (eobp)))
412 (forward-line))
413 (when (eobp)
414 (error "Don't know where to insert the header"))
415 (open-line 1)
416 (insert "#include " (if localp "\"\"" "<>"))
417 (backward-char)
418 (insert path)
419 (move-beginning-of-line 1)
420 (setq start (point))
421 (forward-line)
422 (while (and (looking-at re)
423 (not (eobp)))
424 (forward-line))
425 (sort-lines nil start (point)))))
426 (define-key c-mode-map (kbd "C-c C-a") #'op/c-add-include))
428 (with-eval-after-load 'perl-mode
429 (setq perl-indent-level 8))
431 (with-eval-after-load 'sh-script
432 (setq sh-basic-offset 8
433 sh-indent-after-loop-construct 8
434 sh-indent-after-continuation nil))
438 (setq eshell-hist-ignoredups t)
440 (defun op/eshell-bufname (dir)
441 (concat "*eshell " (expand-file-name dir) "*"))
443 (defun op/eshell (arg)
444 "Run or jump to eshell in current project.
445 If called with prefix argument ARG always create a new eshell
446 buffer."
447 (interactive "P")
448 (let* ((proj (project-current))
449 (dir (if (and proj (not arg))
450 (project-root proj)
451 default-directory))
452 (default-directory dir)
453 (eshell-buffer-name (let ((name (op/eshell-bufname dir)))
454 (if arg
455 (generate-new-buffer name)
456 name))))
457 (eshell)))
458 (define-key global-map (kbd "C-c e") #'op/eshell)
460 (with-eval-after-load 'eshell
461 (setq eshell-save-history-on-exit t
462 eshell-history-size 1024
464 eshell-compl-dir-ignore
465 "\\`\\(\\.\\.?\\|CVS\\|\\.svn\\|\\.git\\|\\.got\\)/\\'")
467 (defun op/eshell-after-cd (&rest _)
468 (rename-buffer (op/eshell-bufname default-directory) t))
470 (advice-add #'eshell/cd :after #'op/eshell-after-cd))
472 (with-eval-after-load 'esh-mode
473 (defun op/clear-eshell ()
474 (interactive "")
475 (let ((inhibit-read-only t))
476 (erase-buffer)
477 (eshell-send-input)))
479 (define-key eshell-command-map (kbd "M-o") #'op/clear-eshell))
482 ;; sndio.el
483 (unless (package-installed-p 'sndio)
484 (package-install-file "~/w/sndio.el/sndio.el"))
487 ;; saturn
488 (unless (package-installed-p 'saturn)
489 (package-install-file "~/w/saturn/GUI/saturn.el"))
492 ;; simple-pass
493 (unless (package-installed-p 'simple-pass)
494 (package-install-file "~/.emacs.d/simple-pass.el"))
495 (define-key global-map (kbd "C-z p") #'simple-pass-copy)
499 ;; elfeed
501 (define-key global-map (kbd "C-x w") #'elfeed)
502 (with-eval-after-load 'elfeed
503 (define-key elfeed-show-mode-map (kbd "q") #'delete-window)
504 (define-key elfeed-show-mode-map (kbd "S-SPC") #'scroll-down-command)
505 (define-key elfeed-show-mode-map (kbd "M-SPC") #'scroll-down-command)
506 (setq elfeed-show-entry-switch #'pop-to-buffer
507 elfeed-feeds
508 '("https://undeadly.org/cgi?action=rss&full=yes&items=10"
509 "http://www.tedunangst.com/flak/rss"
510 "https://www.dragonflydigest.com/feed"
511 "https://www.mirbsd.org/news.rss"
512 "https://www.mirbsd.org/announce.rss"
513 "https://bentsukun.ch/index.xml"
514 "https://drewdevault.com/feed.xml"
515 "https://www.cambus.net/atom.xml"
516 "https://dataswamp.org/~solene/rss.xml"
517 "https://briancallahan.net/blog/feed.xml"
518 "https://www.poolp.org/index.xml"
519 "https://jcs.org/rss"
520 "https://sanctum.geek.nz/arabesque/feed/"
521 "https://tech.toryanderson.com/"
522 "https://alexschroeder.ch/wiki?action=journal;search=-tag:rpg -tag:rsp;lang=en;title=English Diary without RPG Pages"
523 "http://boston.conman.org/bostondiaries.rss"
524 "https://emacsninja.com/feed.atom"
525 "https://bsdly.blogspot.com/feeds/posts/default"
526 "https://crawshaw.io/atom.xml"
527 "https://nullprogram.com/feed/"
528 "http://pragmaticemacs.com/feed/"
529 "https://emacsnotes.wordpress.com/feed/"
530 "https://metaredux.com/feed.xml"
531 "https://emacsredux.com/atom.xml"
532 "https://endlessparentheses.com/atom.xml"
533 "https://www.masteringemacs.org/feed"
534 "https://cestlaz.github.io/rss.xml"
535 "https://utcc.utoronto.ca/~cks/space/blog/?atom"
536 "https://irreal.org/blog/?feed=rss2"
537 "https://jao.io/blog/rss.xml"
538 "https://planet.lisp.org/rss20.xml"
539 "https://insideclojure.org/feed.xml"
540 "https://tech.toryanderson.com/index.xml"
541 "https://vermaden.wordpress.com/feed/"
542 "https://www.arp242.net/feed.xml"
543 "https://tymoon.eu/api/reader/atom"
544 "https://venam.nixers.net/blog/feed.xml"
545 "https://www.omarpolo.com/rss.xml"
546 "https://owarisubs.lacumpa.biz/feed/"
547 "https://asenshi.moe/feed/"
548 "https://godotengine.org/rss.xml"
549 "https://gemini.it.abiscuola.com/gemlog/rss"
551 "https://adventofcomputing.libsyn.com/rss"
553 "https://github.com/go-gitea/gitea/releases.atom"
555 "https://nitter.pussthecat.org/NanoRaptor/rss"
557 "https://github.com/yshui/picom/releases.atom"
558 "https://github.com/vslavik/poedit/releases.atom"
559 "https://github.com/TokTok/c-toxcore/releases.atom"
560 "https://github.com/alexander-akhmetov/python-telegram/releases.atom"
561 "https://github.com/paul-nameless/tg/releases.atom"
562 "https://github.com/YACReader/yacreader/releases.atom"
563 "https://github.com/luarocks/luarocks/releases.atom"
564 "https://github.com/okbob/pspg/releases.atom"
565 "https://github.com/taisei-project/taisei/releases.atom"
566 "https://github.com/recp/cglm/releases.atom"
567 "https://github.com/SCons/scons/releases.atom"
568 "https://git.sr.ht/~rjarry/aerc/refs/rss.xml"
570 "https://causal.agency/list/pounce.atom"
572 "https://www.crimsonmagic.me/feed/"
573 "https://fullybookedtls.wordpress.com/feed/"
575 "https://draculadaily.substack.com/feed")))
577 (setq shackle-default-rule nil
578 shackle-rules
579 (let ((repls "\\*\\(cider-repl\\|sly-mrepl\\|ielm\\)")
580 (godot "\\*godot - .*\\*")
581 (vcs "\\*\\(Flymake\\|Package-Lint\\|vc-\\(git\\|got\\) :\\).*")
582 (elfeed "\\*elfeed-entry\\*")
583 (vmd "\\*vmd console .*"))
584 `(("*Async Shell Command*" :ignore t)
585 (,repls :regexp t
586 :align below
587 :size 0.3)
588 (,godot :regexp t
589 :align t
590 :size 0.3)
591 (occur-mode :select t
592 :align right
593 :size 0.3)
594 (diff-mode :select t)
595 (help-mode :select t
596 :align left
597 :size 0.3)
598 (,vcs :regexp t
599 :align above
600 :size 0.15
601 :select t)
602 (,elfeed :regexp t
603 :align t
604 :select t
605 :size 0.75)
606 (,vmd :regexp t
607 :align below
608 :select t
609 :size 0.3))))
610 (shackle-mode +1)
612 ;; (setq display-buffer-alist nil)
614 (define-key global-map (kbd "M-g e") #'embark-act)
616 (with-eval-after-load 'embark
617 (defun op/target-filename+line ()
618 "Target a file with optional line number: file[:number]."
619 (save-excursion
620 (let* ((beg (progn (skip-chars-backward "^[:space:]\n")
621 (point)))
622 (end (progn (skip-chars-forward "^[:space:]\n")
623 (point)))
624 (str (buffer-substring-no-properties beg end)))
625 (save-match-data
626 (when (and (progn (goto-char beg)
627 (ffap-file-at-point))
628 (string-match ".+\\(:[[:digit:]]+\\)?:?" str))
629 `(file ,str ,beg . ,end))))))
631 (add-to-list 'embark-target-finders #'op/target-filename+line)
633 (defun op/acme-find-file (filename)
634 "Visit FILENAME like `find-file', but also jump to line if provided."
635 (save-match-data
636 (if (not (string-match "\\(.+\\):\\([[:digit:]]+\\)" filename))
637 (find-file filename)
638 (let ((path (match-string 1 filename))
639 (line (string-to-number (match-string 2 filename))))
640 (with-current-buffer (find-file path)
641 (goto-line line))))))
643 (define-key embark-file-map (kbd "RET") #'op/acme-find-file))