]> Git — Sourcephile - julm/julm-nix.git/blob - home-manager/profiles/emacs/config.el
nix: update nixpkgs
[julm/julm-nix.git] / home-manager / profiles / emacs / config.el
1 ;;; config.el -*- lexical-binding: t; -*-
2
3 ;; DOC: https://git.v0.io/hlissner/doom-emacs/src/commit/a680a4c96d2b57fcb75635bd1a918e1235e72890/docs/api.org
4 ;; DOC: https://github.com/daviwil/emacs-from-scratch
5
6 ;; Line numbers are pretty slow all around. The performance boost of
7 ;; disabling them outweighs the utility of always keeping them on.
8 (setq display-line-numbers-type nil)
9 (global-visual-line-mode t)
10
11 ;; Focus new window after splitting
12 (setq evil-split-window-below t
13 evil-vsplit-window-right t
14 )
15
16 ;; Undo
17 (setq undo-tree-auto-save-history t
18 undo-tree-history-directory-alist '(("." . "~/.cache/emacs/undo"))
19 )
20
21 ;; Fonts
22 (setq doom-font-increment 1
23 doom-font-size 9
24 ;doom-font-name "DejaVu Sans Mono"
25 doom-font-name "Hack"
26 ;doom-font-name "Unifont"
27 doom-font (font-spec :family doom-font-name :size doom-font-size :antialias t)
28 doom-unicode-font (font-spec :family "Symbola" :antialias t)
29 doom-variable-pitch-font (font-spec :family doom-font-name :antialias t)
30 ivy-posframe-font (font-spec :family doom-font-name :antialias t)
31 )
32 (setq x-underline-at-descent-line t)
33
34 ;; Dashboard
35 ;;(setq +doom-dashboard-banner-file (expand-file-name "banner.png" doom-private-dir))
36 (defun bury-messages-and-scratch ()
37 (mapcar #'bury-buffer '("*Messages*" "*scratch*")))
38 (add-hook 'emacs-startup-hook #'bury-messages-and-scratch)
39
40 ;; Formatting
41 (setq haskell-stylish-on-save nil)
42 (setq lsp-haskell-formatting-provider "fourmolu")
43 (setq +format-on-save-enabled-modes
44 '(not emacs-lisp-mode ; works well enough without it
45 sql-mode ; sqlformat is broken
46 tex-mode ; latexindent is broken
47 latex-mode ; latexindent is broken
48 bibtex-mode ; is broken
49 ess-r-mode ; styler takes forever
50 )
51 )
52
53 ;; Theming
54 (setq doom-theme 'doom-vibrant)
55 (custom-theme-set-faces! '(doom-vibrant)
56 '(default :background "black" :foreground "white")
57 '(hl-line :background "black")
58 '(cursor :background "DarkOrange" :foreground "black")
59 ;; Haskell colors
60 '(font-lock-string-face :foreground "magenta")
61 '(highlight-numbers-number :foreground "DeepSkyBlue" :bold t)
62 '(font-lock-comment-face :foreground "cyan3")
63 '(font-lock-doc-face :foreground "cyan1")
64 ;'(haskell-constructor-face :foreground "#c4451d")
65 ;'(haskell-keyword-face :foreground "#af005f")
66 ;'(haskell-keyword-face :foreground "RoyalBlue")
67 ;'(haskell-keyword-face :foreground "#44385f")
68 ;'(haskell-keyword-face :foreground "#906238" :bold t)
69 ;'(haskell-keyword-face :foreground "green4" :bold t)
70 '(haskell-keyword-face :foreground "LightGreen" :bold nil)
71 ;'(haskell-pragma-face :foreground "#2aa198")
72 '(haskell-pragma-face :foreground "#8f4e8b")
73 ;'(haskell-type-face :foreground "#9e358f")
74 '(haskell-operator-face :foreground "yellow" :bold nil)
75 ;'(haskell-type-face :foreground "SaddleBrown")
76 ;'(haskell-constructor-face :foreground "darkgoldenrod4")
77 '(haskell-definition-face :foreground "white" :bold nil)
78 '(swiper-line-face :background "grey15")
79 '(swiper-match-face-1 :foreground "grey50" :background "black") ; what is between matches
80 '(swiper-match-face-2 :foreground "black" :background "yellow2")
81 '(swiper-match-face-3 :foreground "black" :background "yellow3")
82 '(swiper-match-face-4 :foreground "black" :background "yellow4")
83 '(swiper-background-match-face-2 :foreground "black" :background "yellow2")
84 '(swiper-background-match-face-3 :foreground "black" :background "yellow3")
85 '(swiper-background-match-face-4 :foreground "black" :background "yellow4")
86 '(evil-ex-lazy-highlight :foreground "black" :background "yellow2")
87 '(region :foreground "black" :background "yellow") ; selected area
88 '(doom-modeline-buffer-modified :foreground "orange")
89 '(git-gutter-fr:added :foreground "green4" :background "black")
90 '(git-gutter-fr:deleted :foreground "red4" :background "black")
91 '(git-gutter-fr:modified :foreground "orange4" :background "black")
92 '(flycheck-fringe-error :foreground "red")
93 '(flycheck-fringe-warning :foreground "orange")
94 '(flycheck-fringe-info :foreground "purple")
95 '(flycheck-info :underline '(:color "SkyBlue4" :style wave))
96 '(flycheck-warning :underline '(:color "orange" :style wave))
97 '(flycheck-error :underline '(:color "red" :style wave))
98 '(warning :foreground "orange")
99 '(error :foreground "red")
100 '(ivy-minibuffer-match-face-1 :foreground "grey50" :background "black") ; what is between matches
101 '(ivy-minibuffer-match-face-2 :foreground "black" :background "yellow2")
102 '(ivy-minibuffer-match-face-3 :foreground "black" :background "yellow3")
103 '(ivy-minibuffer-match-face-4 :foreground "black" :background "yellow4")
104 ; Violet
105 ;'(haskell-operator-face :foreground "yellow3")
106 ;'(haskell-type-face :foreground "#5a4e82")
107 ;'(haskell-constructor-face :foreground "#8a4f88")
108 ;'(haskell-constructor-face :foreground "#8a4c87")
109 '(haskell-constructor-face :foreground "white" :bold t)
110 ; Almost the same as haskell-constructor-face
111 ; because that pattern does not match on type-contexts correctly
112 '(haskell-type-face :foreground "white" :bold t)
113 '(lsp-face-highlight-read :background "gray10")
114 '(lsp-face-highlight-write :background "gray10")
115 '(mode-line :background "gray20")
116 '(mode-line-inactive :background "gray5")
117 '(solaire-default-face :background "gray10")
118 '(solaire-mode-line-face :background "gray20")
119 '(solaire-mode-line-inactive-face :background "gray5")
120 '(doom-modeline-project-dir :foreground "DeepSkyBlue" :bold t)
121 ;'(magit-diff-context-highlight :foreground "white" :background "black")
122 '(magit-diff-added-highlight :foreground "green")
123 '(magit-diff-removed-highlight :foreground "red")
124 ;;'(font-lock-comment-face ((t (:foreground "cyan" :italic t :slant oblique))))
125 ;;'(font-lock-comment-delimiter-face ((t (:foreground "cyan"))))
126 ;;'(fringe ((t (:foreground "red" :background "black"))))
127 ;;'(whitespace-indentation ((t (:foreground "gray50" :bold t))))
128 ;;'(whitespace-space ((t (:foreground "black" :bold t))))
129 ;;'(whitespace-tab ((t (:foreground "gray50" :bold t))))
130 ;;'(whitespace-trailing ((t (:foreground "red" :bold t))))
131 ;;'(font-lock-builtin-face ((t (:foreground "yellow" :weight bold))))
132 ;;'(font-lock-keyword-face ((t (:foreground "yellow" :weight bold))))
133 ;;'(font-lock-string-face ((t (:foreground "magenta"))))
134 ;;'(font-lock-variable-name-face ((t (:foreground "SpringGreen3" :weight bold))))
135 ;;'(nix-antiquote-face ((t (:foreground "blue"))))
136 ;;'(mode-line ((t (:background "midnight blue" :box (:line-width 1 :color "blue") :height 1.0))))
137 ;;'(mode-line-inactive ((t (:background "grey30" :foreground "white" :box (:line-width 1 :color "grey30") :weight light :height 1.0))))
138 ;;'(mode-line ((t (:family "Noto Sans" :height 0.9))))
139 ;;'(mode-line-inactive ((t (:family "Noto Sans" :height 0.9))))
140 ;;'(solaire-mode-line-inactive-face ((t (:background "gray10"))))
141 )
142
143 ;; polymode
144 (use-package! polymode)
145 (define-hostmode poly-haskell-hostmode
146 :mode 'haskell-mode)
147 ;; Support org tables in Haskell files
148 (defun pm--org-table-tail-matcher (ahead)
149 (when (re-search-forward "^[^|]" nil t ahead)
150 (cons (match-beginning 0) (match-end 0))))
151 (define-innermode poly-haskell-org-table-innermode
152 :mode 'org-mode
153 :head-matcher "^|.*"
154 :tail-matcher #'pm--org-table-tail-matcher
155 :head-mode 'body
156 :tail-mode 'host)
157 (define-polymode poly-haskell-mode
158 :hostmode 'poly-haskell-hostmode
159 :innermodes '(poly-haskell-org-table-innermode))
160
161 ;; Language Server Protocol
162 (setq ;+lsp-prompt-to-install-server 'quiet
163 ;lsp-enable-file-watchers nil
164 ;lsp-enable-indentation nil
165 ;lsp-enable-on-type-formatting nil
166 ;lsp-enable-symbol-highlighting nil
167 lsp-enable-symbol-highlighting nil ; slow
168 lsp-ui-doc-enable nil ; slow
169 ;lsp-ui-sideline-enable nil ; not anymore useful than flycheck
170 ;lsp-ui-peek-enable t
171 ;lsp-ui-peek-always-show nil
172 ;lsp-ui-flycheck-enable t
173 ;lsp-ui-flycheck-live-reporting t
174 ;; Disable help mouse-overs for mode-line segments (i.e. :help-echo text).
175 ;; They're generally unhelpful and only add confusing visual clutter.
176 mode-line-default-help-echo nil
177 show-help-function nil
178 global-prettify-symbols-mode nil
179 prettify-symbols-mode -1
180 treemacs-position 'right
181 treemacs-project-follow-mode t
182 lsp-treemacs-errors-position-params `((side . right))
183 lsp-log-io nil ; Only for debugging
184 lsp-restart 'auto-restart
185 ; Only load lsp-clients to speed up loading
186 ; See https://github.com/emacs-lsp/lsp-mode/pull/1498
187 lsp-client-packages '(lsp-clients)
188 lsp-ui-sideline-show-code-actions t
189 )
190
191 ;; The modeline is not useful to me in the popup window.
192 ;; It looks much nicer to hide it.
193 (remove-hook 'emacs-everywhere-init-hooks #'hide-mode-line-mode)
194
195 ;;(remove-hook 'window-setup-hook #'doom-init-theme-h)
196 ;;(add-hook 'after-init-hook #'doom-init-theme-h 'append)
197 ;;(delq! t custom-theme-load-path)
198
199 (setq auto-save-default t ; Nobody likes to loose work, I certainly don't
200 confirm-kill-emacs t
201 confirm-kill-processes nil
202 make-backup-files nil
203 password-cache-expiry nil ; I can trust my computers ... can't I?
204 scroll-margin 10
205 ;; scroll-preserve-screen-position 'always ; Don't have `point' jump around
206 truncate-string-ellipsis "…" ; Unicode ellispis are nicer than "...", and also save /precious/ space
207 kill-whole-line t ; Make Ctrl-K remove the whole line, instead of just emptying it
208 undo-limit 80000000 ; Raise undo-limit to 80MB
209 x-stretch-cursor nil ; Disorienting
210 )
211
212 ;; Debugging
213 ;(setq debug-on-quit t)
214
215 ;; Haskell
216 (setq haskell-process-log nil
217 haskell-interactive-popup-errors nil
218 )
219 (add-hook 'haskell-mode-hook
220 (lambda ()
221 (set (make-local-variable 'company-backends)
222 (append '((company-capf company-dabbrev-code))
223 company-backends))))
224 (define-hostmode poly-haskell-hostmode
225 :mode 'haskell-mode)
226
227 ;; Layout
228 (setq split-height-threshold nil
229 split-width-threshold 160
230 )
231
232 ;; vterm
233 (after! vterm
234 (set-popup-rule! "*doom:vterm-popup:*" :side 'right :size 0.33 :vslot -4 :select t :quit nil :ttl 0)
235 (setq vterm-kill-buffer-on-exit t
236 vterm-max-scrollback 10000
237 )
238 )
239
240 (after! flycheck
241 ; flycheck-error-list-buffer
242 (set-popup-rule! (rx bos "*Flycheck errors*" eos) :side 'right :size 0.33)
243 ; M-x lsp-ui-flycheck-list
244 (setq lsp-ui-flycheck-list-position 'right)
245 (add-hook 'flycheck-error-list-mode-hook
246 (lambda () (setq tabulated-list-sort-key (list "Level"))))
247 (setq
248 flycheck-relevant-error-other-file-minimum-level 'error
249 flycheck-relevant-error-other-file-show t
250 )
251 )
252 ;(add-hook 'flycheck-error-list-after-refresh-hook
253 ; (lambda ()
254 ; (with-selected-window (flycheck-get-error-list-window t)
255 ; (fit-window-to-buffer (flycheck-get-error-list-window t) 30))))
256
257 ;; Completing
258 (add-hook 'after-init-hook 'global-company-mode)
259 ;(setq company-idle-delay nil)
260
261 ;(use-package! ivy
262 ; :defer t
263 ; :bind
264 ; (:map ivy-minibuffer-map
265 ; ("RET" . 'ivy-alt-done)
266 ; ("TAB" . 'ivy-alt-done))
267 ; :init
268 ; (setq ivy-extra-directories nil
269 ; )
270 ; )
271
272 ;(add-hook! 'org-mode-hook #'mixed-pitch-mode)
273 ;(add-hook! 'org-mode-hook #'solaire-mode)
274 ;(setq mixed-pitch-variable-pitch-cursor nil)
275
276 ;(add-hook! org-mode :append
277 ; #'visual-line-mode
278 ; #'variable-pitch-mode)
279
280 (setq doom-modeline-enable-word-count nil)
281
282 (map! "C-x b" #'counsel-buffer-or-recentf
283 "C-x C-b" #'counsel-switch-buffer)
284 (defun recentf-track-visited-file (_prev _curr)
285 (and buffer-file-name
286 (recentf-add-file buffer-file-name)))
287 (after! recentf
288 (add-hook 'switch-buffer-functions #'recentf-track-visited-file))
289
290 ;; Org
291 ; DOC: https://rgoswami.me/posts/org-note-workflow/
292 ; ToStudy: https://github.com/abo-abo/orca
293 ; ToStudy: https://github.com/weirdNox/org-noter
294 ; ToStudy: https://github.com/bastibe/org-journal
295 ; ToStudy: https://orgmode.org/manual/Org-Crypt.html
296 ; DOC: http://www.wouterspekkink.org/academia/writing/tool/doom-emacs/2021/02/27/writing-academic-papers-with-org-mode.html
297 ; DOC: https://jonathanabennett.github.io/blog/2019/05/29/writing-academic-papers-with-org-mode/
298 ; ToStudy: https://github.com/org-roam/org-roam-ui
299 ; ToStudy: https://blog.tecosaur.com/tmio/2021-07-31-citations.html
300 ; ToStudy: https://github.com/jkitchin/org-ref-cite
301 (setq org-directory "~/papers/notes")
302 (setq org-noter-notes-search-path '("~/notes/path/"))
303
304 (after! org
305 (setq org-log-done t
306 org-log-into-drawer t
307 org-special-ctrl-a/e t
308 org-special-ctrl-k t
309 ;org-hide-emphasis-markers t
310 )
311 (add-to-list 'org-capture-templates
312 '("e" "English" table-line ; key, name, type
313 (file "english/vocabulary.org") ; target
314 "|%^{English}|%^{Français}|%^{Registre|Courant|Soutenu|Familier}|"
315 :kill-buffer t))
316 (add-to-list 'org-capture-templates
317 '("x" "Expense" plain
318 (file "compta.org")
319 "\n%(org-read-date) * send %^{Send to} %^{For why}\nExpense:Gifts %^{Amount}\n %^{Currency|EUR|USD|JPY}\n Assets:%^{Account||Personal|Home}"))
320 ;; Firefox and Chrome
321 ;(add-to-list 'org-capture-templates
322 ; `("P" "Protocol" entry ; key, name, type
323 ; (file+headline +org-capture-notes-file "Inbox") ; target
324 ; "* %^{Title}\nSource: %u, %c\n #+BEGIN_QUOTE\n%i\n#+END_QUOTE\n\n\n%?"
325 ; :prepend t ; properties
326 ; :kill-buffer t))
327 ;(add-to-list 'org-capture-templates
328 ; `("L" "Protocol Link" entry
329 ; (file+headline +org-capture-notes-file "Inbox")
330 ; "* %? [[%:link][%(transform-square-brackets-to-round-ones \"%:description\")]]\n"
331 ; :prepend t
332 ; :kill-buffer t))
333 ; )
334 )
335
336 (map! :after counsel :map org-mode-map
337 "C-c l l h" #'counsel-org-link)
338 (after! counsel
339 (setq counsel-outline-display-style 'title))
340
341 ;(after! org-id
342 ; ;; Do not create ID if a CUSTOM_ID exists
343 ; (setq org-id-link-to-org-use-id 'create-if-interactive-and-no-custom-id)
344 ; )
345 ;
346 ;(after! org-agenda
347 ; ;; (setq org-agenda-prefix-format
348 ; ;; '((agenda . " %i %-12:c%?-12t% s")
349 ; ;; ;; Indent todo items by level to show nesting
350 ; ;; (todo . " %i %-12:c%l")
351 ; ;; (tags . " %i %-12:c")
352 ; ;; (search . " %i %-12:c")))
353 ; (setq org-agenda-include-diary t)
354 ; )
355 ;
356 ;(use-package! org-roam
357 ; :defer t
358 ; :hook ((after-init . org-roam-mode))
359 ; :custom
360 ; (setq org-roam-directory "~/papers/notes/org-roam")
361 ;
362 ; ;; Let's set up some org-roam capture templates
363 ; (setq org-roam-capture-templates
364 ; '(("d" "default" plain (function org-roam--capture-get-point)
365 ; "%?"
366 ; :file-name "%<%Y-%m-%d-%H%M%S>-${slug}"
367 ; :head "#+title: ${title}\n"
368 ; :unnarrowed t)))
369 ;
370 ; ;; And now we set necessary variables for org-roam-dailies
371 ; (setq org-roam-dailies-capture-templates
372 ; '(("d" "default" entry
373 ; #'org-roam-capture--get-point
374 ; "* %?"
375 ; :file-name "daily/%<%Y-%m-%d>"
376 ; :head "#+title: %<%Y-%m-%d>\n\n")))
377 ; )
378 ;
379 ;(use-package! org-ref
380 ; :after org-roam
381 ; :config
382 ; (setq reftex-default-bibliography bibliography-files
383 ; org-ref-default-bibliography bibliography-files
384 ; org-ref-bibliography-notes "~/papers/notes/org-roam/bibnotes.org" ;; Is this even needed?
385 ; org-ref-notes-directory "~/papers/notes/org-roam"
386 ; org-ref-notes-function 'orb-edit-notes
387 ; ;org-ref-get-pdf-filename-function 'org-ref-get-pdf-filename-helm-bibtex)
388 ; )
389 ;
390 ;(use-package! bibtex-completion
391 ; :defer t
392 ; :config
393 ; (setq bibtex-completion-notes-path "~/papers/notes/org-roam/"
394 ; bibtex-completion-pdf-field "file"
395 ; bibtex-completion-bibliography bibliography-files
396 ; )
397 ;)
398 ;
399 ;(defvar orb-title-format "${author-or-editor-abbrev} (${date}). ${title}."
400 ; "Format of the title to use for `orb-templates'.")
401 ;
402 ;(use-package! org-roam-bibtex
403 ; :after org-roam
404 ; :hook (org-roam-mode . org-roam-bibtex-mode)
405 ; :bind (:map org-mode-map
406 ; (("C-c n a" . orb-note-actions)))
407 ; :config
408 ; (setq orb-preformat-keywords
409 ; '(("citekey" . "=key=") "title" "date" "author-or-editor-abbrev")
410 ; orb-templates
411 ; `(("r" "ref" plain
412 ; (function org-roam-capture--get-point)
413 ; ""
414 ; :file-name "${citekey}"
415 ; :head ,(s-join "\n"
416 ; (list
417 ; (concat "#+TITLE: " orb-title-format)
418 ; "#+ROAM_KEY: ${ref}"
419 ; ""
420 ; "- tags :: "
421 ; ""
422 ; "* Notes"
423 ; ""))
424 ; :unnarrowed t)
425 ; ("n" "ref + noter" plain
426 ; (function org-roam-capture--get-point)
427 ; ""
428 ; :file-name "${citekey}"
429 ; :head ,(s-join "\n"
430 ; (list
431 ; (concat "#+TITLE: " orb-title-format)
432 ; "#+ROAM_KEY: ${ref}"
433 ; ""
434 ; "- tags :: "
435 ; ""
436 ; "* Annotations :noter:"
437 ; ":PROPERTIES:"
438 ; ":NOTER_DOCUMENT: %(orb-process-file-field \"${citekey}\")"
439 ; ":NOTER_PAGE:"
440 ; ":END:"
441 ; ""))))))
442 ;
443 ;(map! :after pdf-tools
444 ; :map pdf-view-mode-map
445 ; :gn "q" (lambda ()
446 ; (interactive)
447 ; (if (bound-and-true-p org-noter-doc-mode)
448 ; (org-noter-kill-session)
449 ; (kill-current-buffer)))
450 ; )
451 ;
452 ;(use-package! org-noter
453 ; :after (:any org pdf-view)
454 ; :config
455 ; (setq org-noter-notes-search-path '("~/papers/notes/org-roam")
456 ; org-noter-always-create-frame nil
457 ; )
458 ; )
459
460 ;(setq lsp-lens-mode t)
461 (setq doom-modeline-height 1)
462 (setq doom-modeline-lsp t)
463 ;(setq doom-modeline-minor-modes t)
464 ;(setq lsp-modeline-diagnostics-enable t)
465
466 ;; Indenting
467 (setq-default tab-width 2)
468 (setq indent-tabs-mode nil)
469
470 ;; Searching
471 (global-superword-mode t)
472 ; https://emacs.stackexchange.com/questions/9583/how-to-treat-underscore-as-part-of-the-word
473 (modify-syntax-entry ?_ "w")
474 (defun swiper-all/search-word-at-point ()
475 (interactive)
476 (swiper-all (format "\\_<%s\\_>" (thing-at-point 'word))))
477 ; Highlight without jumping to the next match
478 ; See: https://emacs.stackexchange.com/questions/52411/evil-star-visualstar-without-moving-the-cursor
479 (defun search-word-at-point ()
480 (interactive)
481 (evil-search (progn (evil-ex-search-word-forward)
482 (evil-ex-search-previous)
483 )))
484 (defun search-unbounded-word-at-point ()
485 (interactive)
486 (evil-search (progn (evil-ex-search-unbounded-word-forward)
487 (evil-ex-search-unbounded-word-previous)
488 )))
489 (after! (ivy swiper)
490 (setq case-fold-search nil ; case-sensitive search by default
491 ivy-case-fold-search-default nil ; case-sensitive search by default
492 ivy-count-format "(%d/%d) "
493 ivy-height 10
494 ;; Press C-p and Enter to select current input as candidate
495 ;; https://oremacs.com/2017/11/30/ivy-0.10.0/
496 ivy-use-selectable-prompt t
497 ivy-use-virtual-buffers t
498 )
499 (add-to-list 'ivy-re-builders-alist `(swiper . ivy--regex))
500 (add-to-list 'ivy-re-builders-alist `(swiper-all . ivy--regex))
501 (add-to-list 'ivy-re-builders-alist `(read-file-name-internal . ivy--regex-fuzzy))
502 )
503 (after! evil
504 (setq which-key-min-display-lines 15
505 ; https://github.com/doomemacs/doomemacs/issues/5622#issuecomment-946760888
506 which-key-allow-imprecise-window-fit nil
507 )
508 ;(general-define-key "C-s" '(counsel-grep-or-swiper :which-key "search"))
509 ;(general-define-key :keymaps '(swiper-map) "C-u" '(lambda () (interactive) (kill-line 0)))
510 ;(general-nvmap "/" '(counsel-grep-or-swiper :which-key "search in buffer"))
511 (evil-define-key 'normal global-map
512 (kbd "/") 'swiper
513 (kbd "C-f") 'swiper-all
514 (kbd "C-/") 'swiper-all/search-word-at-point
515 (kbd "*") 'search-word-at-point
516 (kbd "g*") 'search-unbounded-word-at-point
517 )
518 )
519
520 ;; Editing
521 (after! evil
522 (setq evil-want-fine-undo t
523 )
524 (customize-set-variable 'evil-want-Y-yank-to-eol nil)
525 (evil-define-key 'normal global-map (kbd "K") 'evil-join)
526 (evil-define-key 'insert global-map (kbd "C-u") '(lambda () (interactive) (kill-line 0)))
527 (evil-define-key 'normal global-map (kbd "SPC g d") 'git-gutter:popup-hunk)
528 )
529 (setq +vc-gutter-default-style nil
530 )
531 (customize-set-variable 'git-gutter:update-interval 2)
532 ;(customize-set-variable 'git-gutter:window-width 2)
533 (after! git-gutter-fringe
534 (require 'fringe-helper)
535 ; Narrower vertical bar, matching the one in the "+" of git-gutter-fr:added
536 (fringe-helper-define 'git-gutter-fr:modified nil
537 "...XX..."
538 "...XX..."
539 ".XXXXXX."
540 ".XXXXXX."
541 "...XX..."
542 "...XX..."
543 ".XXXXXX."
544 ".XXXXXX.")
545 ; Narrower horizontql bar, matching the one in the "+" of git-gutter-fr:added
546 (fringe-helper-define 'git-gutter-fr:deleted nil
547 "........"
548 "........"
549 "........"
550 ".XXXXXX."
551 ".XXXXXX."
552 "........"
553 "........"
554 "........")
555 )
556
557
558 ;; Folding
559 (defun set-selective-display/at-point (&optional level)
560 "Fold text indented same of more than the cursor.
561 If level is set, set the indent level to LEVEL.
562 If 'selective-display' is already set to LEVEL,
563 calling it again will unset 'selective-display' by setting it to 0."
564 (interactive "P")
565 (if (eq selective-display (1+ (current-column)))
566 (set-selective-display 0)
567 (set-selective-display (or level (1+ (current-column))))))
568 (after! evil
569 (evil-define-key 'normal global-map
570 (kbd "C-d") 'set-selective-display/at-point)
571 )
572
573 ;; Navigating
574 ;; DOC: https://github.com/noctuid/evil-guide
575 (after! evil
576 (setq evil-cross-lines t
577 evil-ex-search-case 'sensitive
578 evil-move-cursor-back nil
579 evil-search-wrap nil
580 evil-want-C-i-jump nil
581 )
582
583 ;; Switching buffers
584 (evil-define-key 'motion 'global
585 (kbd "<C-i>") 'evil-prev-buffer ; Does not work without the angles ('<' and '>')
586 (kbd "C-k") 'evil-next-buffer
587 (kbd "C-x k") 'kill-current-buffer
588 (kbd "C-m") 'counsel-switch-buffer
589 )
590 ;(define-key evil-normal-state-map [tab] 'evil-prev-buffer)
591
592 ;; Jumping
593 (evil-define-key 'motion 'global
594 (kbd "C-u") 'better-jumper-jump-backward
595 (kbd "C-o") 'better-jumper-jump-forward
596 )
597 ;; Jumping
598 ;(evil-define-key '(motion normal visual) 'global
599 ;(kbd "C--") 'doom/decrease-font-size
600 ;(kbd "C-=") 'doom/increase-font-size
601 ; )
602
603 ;; Moving with ijkl (instead of hjkl)
604 (evil-define-key '(motion normal visual) 'global
605 (kbd "i") 'evil-previous-visual-line
606 (kbd "j") 'evil-backward-char
607 (kbd "k") 'evil-next-visual-line
608 (kbd "h") 'evil-insert
609 )
610
611 ;; Switching windows with SPC-w + ijkl (instead of hjkl)
612 (define-key evil-window-map "i" 'evil-window-up)
613 (define-key evil-window-map "I" 'evil-window-move-very-top)
614 (define-key evil-window-map "j" 'evil-window-left)
615 (define-key evil-window-map "J" 'evil-window-move-far-left)
616 (define-key evil-window-map "k" 'evil-window-down)
617 (define-key evil-window-map "K" 'evil-window-move-very-bottom)
618 ;(define-key evil-emacs-state-map "\C-w" 'evil-window-map)
619 ;;(evil-define-key 'window global-map "l" 'evil-window-right)
620 ;;(evil-define-key 'window global-map "L" 'evil-window-move-far-right)
621
622 ;; ijkl in Dired
623 ;;(evil-define-key 'normal dired-mode-map "i" 'evil-previous-line)
624
625 ;; Errors
626 (evil-define-key 'motion 'global
627 (kbd "C-j") 'previous-error
628 (kbd "C-l") 'next-error
629 )
630 ;(bind-key "C-j" #'previous-error)
631 ;(bind-key "C-l" #'next-error)
632 )
633 (after! auto-yasnippet
634 (evil-define-key '(motion normal) 'global
635 (kbd "C-<tab>") 'evil-switch-to-windows-last-buffer
636 )
637 )
638 (after! (evil magit evil-collection-magit)
639 (evil-define-key '(motion normal) magit-mode-map
640 (kbd "C-i") 'evil-prev-buffer
641 (kbd "i") 'evil-previous-visual-line
642 (kbd "k") 'evil-next-visual-line
643 (kbd "C-k") 'evil-next-buffer
644 (kbd "j") 'magit-section-backward
645 (kbd "l") 'magit-section-forward
646 )
647 )
648 (after! (evil magit git-rebase)
649 (evil-define-key '(motion normal) git-rebase-mode-map
650 (kbd "C-i") 'evil-prev-buffer
651 (kbd "i") 'evil-previous-visual-line
652 (kbd "k") 'evil-next-visual-line
653 (kbd "C-k") 'evil-next-buffer
654 (kbd "j") 'evil-backward-char
655 )
656 )
657 ;;(eval-after-load 'evil ; to run after evil-integration.el
658 ;; '(progn
659 ;; (define-key Buffer-menu-mode-map "\C-i" 'evil-prev-buffer)
660 ;; (define-key Buffer-menu-mode-map "\C-k" 'evil-next-buffer)
661 ;; (define-key messages-buffer-mode-map "\C-i" 'evil-prev-buffer)
662 ;; (define-key messages-buffer-mode-map "\C-k" 'evil-next-buffer)
663 ;; (define-key completion-list-mode-map "\C-i" 'evil-prev-buffer)
664 ;; (define-key completion-list-mode-map "\C-k" 'evil-next-buffer)
665 ;; ;(define-key custom-theme-mode-map "\C-i" 'evil-prev-buffer)
666 ;; ;(define-key custom-theme-mode-map "\C-k" 'evil-next-buffer)
667 ;; )
668 ;; )
669
670 ;;(with-eval-after-load 'evil-maps
671 ;; (define-key evil-motion-state-map (kbd "TAB") nil))
672
673 ;; Feed reader
674 ; See also: Managing ArXiv RSS Feeds in Emacs https://cundy.me/post/elfeed/
675
676 (setq
677 elfeed-enable-web-interface t
678 url-queue-timeout 30
679 )
680 ;(global-set-key (kbd "C-x w") 'elfeed)
681
682 (defun elfeed-mark-all-as-read ()
683 (interactive)
684 (mark-whole-buffer)
685 (elfeed-search-untag-all-unread))
686
687 ; Functions to support syncing .elfeed between machines
688 ; makes sure elfeed reads index from disk before launching
689 (defun elfeed-load-db-and-open ()
690 "Wrapper to load the elfeed db from disk before opening"
691 (interactive)
692 (elfeed-db-load)
693 (elfeed)
694 (elfeed-search-update--force))
695
696 ; Write to disk when quiting
697 (defun elfeed-save-db-and-bury ()
698 "Wrapper to save the elfeed db to disk before burying buffer"
699 (interactive)
700 (elfeed-db-save)
701 (quit-window))
702
703 (defun elfeed-toggle-star ()
704 "Toggle star"
705 (interactive)
706 (elfeed-search-tag-all '*)
707 )
708 (after! (evil elfeed evil-collection-elfeed)
709 (evil-define-key 'motion elfeed-search-mode-map "m" #'elfeed-toggle-star)
710 )
711
712 (defun elfeed-org-update-incremental ()
713 "Automatically update the feeds from feeds.org when updated"
714 (setq my-elfeed-org-last (or (and (boundp 'elfeed-feeds) elfeed-feeds) nil))
715 (elfeed)
716 (setq my-elfeed-org-current elfeed-feeds)
717 (let ((elfeed-feeds (-difference my-elfeed-org-current my-elfeed-org-last)))
718 ;; You don't need the line below if you don't want to see a message about what feeds are being updated
719 (message "%s" elfeed-feeds)
720 (mapc #'elfeed-update-feed (elfeed--shuffle (elfeed-feed-list))))
721 (setq elfeed-feeds my-elfeed-org-current))
722