;;; config.el -*- lexical-binding: t; -*-

;; DOC: https://git.v0.io/hlissner/doom-emacs/src/commit/a680a4c96d2b57fcb75635bd1a918e1235e72890/docs/api.org
;; DOC: https://github.com/daviwil/emacs-from-scratch

;; Line numbers are pretty slow all around. The performance boost of
;; disabling them outweighs the utility of always keeping them on.
(setq display-line-numbers-type nil)
(global-visual-line-mode t)

;; Focus new window after splitting
(setq evil-split-window-below t
      evil-vsplit-window-right t
      )

;; Undo
(setq undo-tree-auto-save-history t
      undo-tree-history-directory-alist '(("." . "~/.cache/emacs/undo"))
      )

;; Fonts
(setq doom-font-increment 1
      doom-font-size 9
      ;doom-font-name "DejaVu Sans Mono"
      doom-font-name "Hack"
      ;doom-font-name "Unifont"
      doom-font (font-spec :family doom-font-name :size doom-font-size :antialias t)
      doom-unicode-font (font-spec :family "Symbola" :antialias t)
      doom-variable-pitch-font (font-spec :family doom-font-name :antialias t)
      ivy-posframe-font (font-spec :family doom-font-name :antialias t)
      )
(setq x-underline-at-descent-line t)

;; Dashboard
;;(setq +doom-dashboard-banner-file (expand-file-name "banner.png" doom-private-dir))
(defun bury-messages-and-scratch ()
       (mapcar #'bury-buffer '("*Messages*" "*scratch*")))
(add-hook 'emacs-startup-hook #'bury-messages-and-scratch)

;; Formatting
(setq haskell-stylish-on-save nil)
(setq lsp-haskell-formatting-provider "fourmolu")
(setq +format-on-save-enabled-modes
      '(not emacs-lisp-mode ; works well enough without it
            sql-mode        ; sqlformat is broken
            tex-mode        ; latexindent is broken
            latex-mode      ; latexindent is broken
            bibtex-mode     ; is broken
            ess-r-mode      ; styler takes forever
            )
      )

;; Theming
(setq doom-theme 'doom-vibrant)
(custom-theme-set-faces! '(doom-vibrant)
  '(default :background "black" :foreground "white")
  '(hl-line :background "black")
  '(cursor :background "DarkOrange" :foreground "black")
  ;; Haskell colors
  '(font-lock-string-face :foreground "magenta")
  '(highlight-numbers-number :foreground "DeepSkyBlue" :bold t)
  '(font-lock-comment-face :foreground "cyan3")
  '(font-lock-doc-face :foreground "cyan1")
  ;'(haskell-constructor-face :foreground "#c4451d")
  ;'(haskell-keyword-face :foreground "#af005f")
  ;'(haskell-keyword-face :foreground "RoyalBlue")
  ;'(haskell-keyword-face :foreground "#44385f")
  ;'(haskell-keyword-face :foreground "#906238" :bold t)
  ;'(haskell-keyword-face :foreground "green4" :bold t)
  '(haskell-keyword-face :foreground "LightGreen" :bold nil)
  ;'(haskell-pragma-face :foreground "#2aa198")
  '(haskell-pragma-face :foreground "#8f4e8b")
  ;'(haskell-type-face :foreground "#9e358f")
  '(haskell-operator-face :foreground "yellow" :bold nil)
  ;'(haskell-type-face :foreground "SaddleBrown")
  ;'(haskell-constructor-face :foreground "darkgoldenrod4")
  '(haskell-definition-face :foreground "white" :bold nil)
  '(swiper-line-face :background "grey15")
  '(swiper-match-face-1 :foreground "grey50" :background "black") ; what is between matches
  '(swiper-match-face-2 :foreground "black" :background "yellow2")
  '(swiper-match-face-3 :foreground "black" :background "yellow3")
  '(swiper-match-face-4 :foreground "black" :background "yellow4")
  '(swiper-background-match-face-2 :foreground "black" :background "yellow2")
  '(swiper-background-match-face-3 :foreground "black" :background "yellow3")
  '(swiper-background-match-face-4 :foreground "black" :background "yellow4")
  '(evil-ex-lazy-highlight :foreground "black" :background "yellow2")
  '(region :foreground "black" :background "yellow") ; selected area
  '(doom-modeline-buffer-modified :foreground "orange")
  '(git-gutter-fr:added :foreground "green4" :background "black")
  '(git-gutter-fr:deleted :foreground "red4" :background "black")
  '(git-gutter-fr:modified :foreground "orange4" :background "black")
  '(flycheck-fringe-error :foreground "red")
  '(flycheck-fringe-warning :foreground "orange")
  '(flycheck-fringe-info :foreground "purple")
  '(flycheck-info :underline '(:color "SkyBlue4" :style wave))
  '(flycheck-warning :underline '(:color "orange" :style wave))
  '(flycheck-error :underline '(:color "red" :style wave))
  '(warning :foreground "orange")
  '(error :foreground "red")
  '(ivy-minibuffer-match-face-1 :foreground "grey50" :background "black") ; what is between matches
  '(ivy-minibuffer-match-face-2 :foreground "black" :background "yellow2")
  '(ivy-minibuffer-match-face-3 :foreground "black" :background "yellow3")
  '(ivy-minibuffer-match-face-4 :foreground "black" :background "yellow4")
  ; Violet
  ;'(haskell-operator-face :foreground "yellow3")
  ;'(haskell-type-face :foreground "#5a4e82")
  ;'(haskell-constructor-face :foreground "#8a4f88")
  ;'(haskell-constructor-face :foreground "#8a4c87")
  '(haskell-constructor-face :foreground "white" :bold t)
  ; Almost the same as haskell-constructor-face
  ; because that pattern does not match on type-contexts correctly
  '(haskell-type-face :foreground "white" :bold t)
  '(lsp-face-highlight-read :background "gray10")
  '(lsp-face-highlight-write :background "gray10")
  '(mode-line :background "gray20")
  '(mode-line-inactive :background "gray5")
  '(solaire-default-face :background "gray10")
  '(solaire-mode-line-face :background "gray20")
  '(solaire-mode-line-inactive-face :background "gray5")
  '(doom-modeline-project-dir :foreground "DeepSkyBlue" :bold t)
  ;'(magit-diff-context-highlight :foreground "white" :background "black")
  '(magit-diff-added-highlight :foreground "green")
  '(magit-diff-removed-highlight :foreground "red")
  ;;'(font-lock-comment-face ((t (:foreground "cyan" :italic t :slant oblique))))
  ;;'(font-lock-comment-delimiter-face ((t (:foreground "cyan"))))
  ;;'(fringe                 ((t (:foreground "red" :background "black"))))
  ;;'(whitespace-indentation ((t (:foreground "gray50" :bold t))))
  ;;'(whitespace-space       ((t (:foreground "black" :bold t))))
  ;;'(whitespace-tab         ((t (:foreground "gray50" :bold t))))
  ;;'(whitespace-trailing    ((t (:foreground "red" :bold t))))
  ;;'(font-lock-builtin-face ((t (:foreground "yellow" :weight bold))))
  ;;'(font-lock-keyword-face ((t (:foreground "yellow" :weight bold))))
  ;;'(font-lock-string-face  ((t (:foreground "magenta"))))
  ;;'(font-lock-variable-name-face ((t (:foreground "SpringGreen3" :weight bold))))
  ;;'(nix-antiquote-face     ((t (:foreground "blue"))))
  ;;'(mode-line ((t (:background "midnight blue" :box (:line-width 1 :color "blue") :height 1.0))))
  ;;'(mode-line-inactive ((t (:background "grey30" :foreground "white" :box (:line-width 1 :color "grey30") :weight light :height 1.0))))
  ;;'(mode-line ((t (:family "Noto Sans" :height 0.9))))
  ;;'(mode-line-inactive ((t (:family "Noto Sans" :height 0.9))))
  ;;'(solaire-mode-line-inactive-face ((t (:background "gray10"))))
  )

;; polymode
(use-package! polymode)
(define-hostmode poly-haskell-hostmode
                 :mode 'haskell-mode)
;; Support org tables in Haskell files
(defun pm--org-table-tail-matcher (ahead)
    (when (re-search-forward "^[^|]" nil t ahead)
          (cons (match-beginning 0) (match-end 0))))
(define-innermode poly-haskell-org-table-innermode
                  :mode 'org-mode
                  :head-matcher "^|.*"
                  :tail-matcher #'pm--org-table-tail-matcher
                  :head-mode 'body
                  :tail-mode 'host)
(define-polymode poly-haskell-mode
                 :hostmode 'poly-haskell-hostmode
                 :innermodes '(poly-haskell-org-table-innermode))

;; Language Server Protocol
(setq ;+lsp-prompt-to-install-server 'quiet
      ;lsp-enable-file-watchers nil
      ;lsp-enable-indentation nil
      ;lsp-enable-on-type-formatting nil
      ;lsp-enable-symbol-highlighting nil
      lsp-enable-symbol-highlighting nil ; slow
      lsp-ui-doc-enable nil ; slow
      ;lsp-ui-sideline-enable nil ; not anymore useful than flycheck
      ;lsp-ui-peek-enable t
      ;lsp-ui-peek-always-show nil
      ;lsp-ui-flycheck-enable t
      ;lsp-ui-flycheck-live-reporting t
      ;; Disable help mouse-overs for mode-line segments (i.e. :help-echo text).
      ;; They're generally unhelpful and only add confusing visual clutter.
      mode-line-default-help-echo nil
      show-help-function nil
      global-prettify-symbols-mode nil
      prettify-symbols-mode -1
      treemacs-position 'right
      treemacs-project-follow-mode t
      lsp-treemacs-errors-position-params `((side . right))
      lsp-log-io nil ; Only for debugging
      lsp-restart 'auto-restart
      ; Only load lsp-clients to speed up loading
      ; See https://github.com/emacs-lsp/lsp-mode/pull/1498
      lsp-client-packages '(lsp-clients)
      lsp-ui-sideline-show-code-actions t
      )

;; The modeline is not useful to me in the popup window.
;; It looks much nicer to hide it.
(remove-hook 'emacs-everywhere-init-hooks #'hide-mode-line-mode)

;;(remove-hook 'window-setup-hook #'doom-init-theme-h)
;;(add-hook 'after-init-hook #'doom-init-theme-h 'append)
;;(delq! t custom-theme-load-path)

(setq auto-save-default t ; Nobody likes to loose work, I certainly don't
      confirm-kill-emacs t
      confirm-kill-processes nil
      make-backup-files nil
      password-cache-expiry nil ; I can trust my computers ... can't I?
      scroll-margin 10
      ;; scroll-preserve-screen-position 'always     ; Don't have `point' jump around
      truncate-string-ellipsis "…" ; Unicode ellispis are nicer than "...", and also save /precious/ space
      kill-whole-line t ; Make Ctrl-K remove the whole line, instead of just emptying it
      undo-limit 80000000 ; Raise undo-limit to 80MB
      x-stretch-cursor nil ; Disorienting
      )

;; Debugging
;(setq debug-on-quit t)

;; Haskell
(setq haskell-process-log nil
      haskell-interactive-popup-errors nil
      )
(add-hook 'haskell-mode-hook
          (lambda ()
            (set (make-local-variable 'company-backends)
                 (append '((company-capf company-dabbrev-code))
                         company-backends))))
(define-hostmode poly-haskell-hostmode
                 :mode 'haskell-mode)

;; Layout
(setq split-height-threshold nil
      split-width-threshold 160
      )

;; vterm
(after! vterm
  (set-popup-rule! "*doom:vterm-popup:*" :side 'right :size 0.33 :vslot -4 :select t :quit nil :ttl 0)
  (setq vterm-kill-buffer-on-exit t
        vterm-max-scrollback 10000
        )
  )

(after! flycheck
  ; flycheck-error-list-buffer
  (set-popup-rule! (rx bos "*Flycheck errors*" eos) :side 'right :size 0.33)
  ; M-x lsp-ui-flycheck-list
  (setq lsp-ui-flycheck-list-position 'right)
  (add-hook 'flycheck-error-list-mode-hook
            (lambda () (setq tabulated-list-sort-key (list "Level"))))
  (setq
    flycheck-relevant-error-other-file-minimum-level 'error
    flycheck-relevant-error-other-file-show t
    )
  )
;(add-hook 'flycheck-error-list-after-refresh-hook
;          (lambda ()
;            (with-selected-window (flycheck-get-error-list-window t)
;                                  (fit-window-to-buffer (flycheck-get-error-list-window t) 30))))

;; Completing
(add-hook 'after-init-hook 'global-company-mode)
;(setq company-idle-delay nil)

;(use-package! ivy
;  :defer t
;  :bind
;  (:map ivy-minibuffer-map
;        ("RET" . 'ivy-alt-done)
;        ("TAB" . 'ivy-alt-done))
;  :init
;  (setq ivy-extra-directories nil
;        )
;  )

;(add-hook! 'org-mode-hook #'mixed-pitch-mode)
;(add-hook! 'org-mode-hook #'solaire-mode)
;(setq mixed-pitch-variable-pitch-cursor nil)

;(add-hook! org-mode :append
;  #'visual-line-mode
;  #'variable-pitch-mode)

(setq doom-modeline-enable-word-count nil)

(map! "C-x b"   #'counsel-buffer-or-recentf
      "C-x C-b" #'counsel-switch-buffer)
(defun recentf-track-visited-file (_prev _curr)
  (and buffer-file-name
       (recentf-add-file buffer-file-name)))
(after! recentf
  (add-hook 'switch-buffer-functions #'recentf-track-visited-file))

;; Org
; DOC: https://rgoswami.me/posts/org-note-workflow/
; ToStudy: https://github.com/abo-abo/orca
; ToStudy: https://github.com/weirdNox/org-noter
; ToStudy: https://github.com/bastibe/org-journal
; ToStudy: https://orgmode.org/manual/Org-Crypt.html
; DOC: http://www.wouterspekkink.org/academia/writing/tool/doom-emacs/2021/02/27/writing-academic-papers-with-org-mode.html
; DOC: https://jonathanabennett.github.io/blog/2019/05/29/writing-academic-papers-with-org-mode/
; ToStudy: https://github.com/org-roam/org-roam-ui
; ToStudy: https://blog.tecosaur.com/tmio/2021-07-31-citations.html
; ToStudy: https://github.com/jkitchin/org-ref-cite
(setq org-directory "~/papers/notes")
(setq org-noter-notes-search-path '("~/notes/path/"))

(after! org
  (setq org-log-done t
        org-log-into-drawer t
        org-special-ctrl-a/e t
        org-special-ctrl-k t
        ;org-hide-emphasis-markers t
        )
  (add-to-list 'org-capture-templates
               '("e" "English" table-line ; key, name, type
                     (file "english/vocabulary.org") ; target
                     "|%^{English}|%^{Français}|%^{Registre|Courant|Soutenu|Familier}|"
                     :kill-buffer t))
  (add-to-list 'org-capture-templates
               '("x" "Expense" plain
                     (file "compta.org")
                     "\n%(org-read-date) * send %^{Send to} %^{For why}\nExpense:Gifts  %^{Amount}\n  %^{Currency|EUR|USD|JPY}\n Assets:%^{Account||Personal|Home}"))
  ;; Firefox and Chrome
  ;(add-to-list 'org-capture-templates
  ;             `("P" "Protocol" entry ; key, name, type
  ;                   (file+headline +org-capture-notes-file "Inbox") ; target
  ;                   "* %^{Title}\nSource: %u, %c\n #+BEGIN_QUOTE\n%i\n#+END_QUOTE\n\n\n%?"
  ;                   :prepend t ; properties
  ;                   :kill-buffer t))
  ;(add-to-list 'org-capture-templates
  ;             `("L" "Protocol Link" entry
  ;                   (file+headline +org-capture-notes-file "Inbox")
  ;                   "* %? [[%:link][%(transform-square-brackets-to-round-ones \"%:description\")]]\n"
  ;                   :prepend t
  ;                   :kill-buffer t))
  ;             )
  )

(map! :after counsel :map org-mode-map
  "C-c l l h" #'counsel-org-link)
(after! counsel
  (setq counsel-outline-display-style 'title))

;(after! org-id
;  ;; Do not create ID if a CUSTOM_ID exists
;  (setq org-id-link-to-org-use-id 'create-if-interactive-and-no-custom-id)
;  )
;
;(after! org-agenda
;  ;; (setq org-agenda-prefix-format
;  ;;       '((agenda . " %i %-12:c%?-12t% s")
;  ;;         ;; Indent todo items by level to show nesting
;  ;;         (todo . " %i %-12:c%l")
;  ;;         (tags . " %i %-12:c")
;  ;;        (search . " %i %-12:c")))
;  (setq org-agenda-include-diary t)
;  )
;
;(use-package! org-roam
;  :defer t
;  :hook ((after-init . org-roam-mode))
;  :custom
;  (setq org-roam-directory "~/papers/notes/org-roam")
;
;  ;; Let's set up some org-roam capture templates
;  (setq org-roam-capture-templates
;        '(("d" "default" plain (function org-roam--capture-get-point)
;                "%?"
;                :file-name "%<%Y-%m-%d-%H%M%S>-${slug}"
;                :head "#+title: ${title}\n"
;                :unnarrowed t)))
;
;  ;; And now we set necessary variables for org-roam-dailies
;  (setq org-roam-dailies-capture-templates
;        '(("d" "default" entry
;           #'org-roam-capture--get-point
;           "* %?"
;           :file-name "daily/%<%Y-%m-%d>"
;           :head "#+title: %<%Y-%m-%d>\n\n")))
;  )
;
;(use-package! org-ref
;  :after org-roam
;  :config
;  (setq reftex-default-bibliography bibliography-files
;        org-ref-default-bibliography bibliography-files
;        org-ref-bibliography-notes "~/papers/notes/org-roam/bibnotes.org"  ;; Is this even needed?
;        org-ref-notes-directory "~/papers/notes/org-roam"
;        org-ref-notes-function 'orb-edit-notes
;        ;org-ref-get-pdf-filename-function 'org-ref-get-pdf-filename-helm-bibtex)
;  )
;
;(use-package! bibtex-completion
;  :defer t
;  :config
;  (setq bibtex-completion-notes-path "~/papers/notes/org-roam/"
;        bibtex-completion-pdf-field "file"
;        bibtex-completion-bibliography bibliography-files
;        )
;)
;
;(defvar orb-title-format "${author-or-editor-abbrev} (${date}).  ${title}."
;  "Format of the title to use for `orb-templates'.")
;
;(use-package! org-roam-bibtex
;  :after org-roam
;  :hook (org-roam-mode . org-roam-bibtex-mode)
;  :bind (:map org-mode-map
;              (("C-c n a" . orb-note-actions)))
;  :config
;  (setq orb-preformat-keywords
;        '(("citekey" . "=key=") "title" "date" "author-or-editor-abbrev")
;        orb-templates
;        `(("r" "ref" plain
;           (function org-roam-capture--get-point)
;           ""
;           :file-name "${citekey}"
;           :head ,(s-join "\n"
;                          (list
;                           (concat "#+TITLE: " orb-title-format)
;                           "#+ROAM_KEY: ${ref}"
;                           ""
;                           "- tags :: "
;                           ""
;                           "* Notes"
;                           ""))
;           :unnarrowed t)
;          ("n" "ref + noter" plain
;           (function org-roam-capture--get-point)
;           ""
;           :file-name "${citekey}"
;           :head ,(s-join "\n"
;                          (list
;                           (concat "#+TITLE: " orb-title-format)
;                           "#+ROAM_KEY: ${ref}"
;                           ""
;                           "- tags :: "
;                           ""
;                           "* Annotations :noter:"
;                           ":PROPERTIES:"
;                           ":NOTER_DOCUMENT: %(orb-process-file-field \"${citekey}\")"
;                           ":NOTER_PAGE:"
;                           ":END:"
;                           ""))))))
;
;(map! :after pdf-tools
;      :map pdf-view-mode-map
;      :gn "q" (lambda ()
;                (interactive)
;                (if (bound-and-true-p org-noter-doc-mode)
;                    (org-noter-kill-session)
;                  (kill-current-buffer)))
;      )
;
;(use-package! org-noter
;  :after (:any org pdf-view)
;  :config
;  (setq org-noter-notes-search-path '("~/papers/notes/org-roam")
;        org-noter-always-create-frame nil
;        )
;  )

;(setq lsp-lens-mode t)
(setq doom-modeline-height 1)
(setq doom-modeline-lsp t)
;(setq doom-modeline-minor-modes t)
;(setq lsp-modeline-diagnostics-enable t)

;; Indenting
(setq-default tab-width 2)
(setq indent-tabs-mode nil)

;; Searching
(global-superword-mode t)
; https://emacs.stackexchange.com/questions/9583/how-to-treat-underscore-as-part-of-the-word
(modify-syntax-entry ?_ "w")
(defun swiper-all/search-word-at-point ()
  (interactive)
  (swiper-all (format "\\_<%s\\_>" (thing-at-point 'word))))
; Highlight without jumping to the next match
; See: https://emacs.stackexchange.com/questions/52411/evil-star-visualstar-without-moving-the-cursor
(defun search-word-at-point ()
  (interactive)
  (evil-search (progn (evil-ex-search-word-forward)
                      (evil-ex-search-previous)
                      )))
(defun search-unbounded-word-at-point ()
  (interactive)
  (evil-search (progn (evil-ex-search-unbounded-word-forward)
                      (evil-ex-search-unbounded-word-previous)
                      )))
(after! (ivy swiper)
  (setq case-fold-search nil ; case-sensitive search by default
        ivy-case-fold-search-default nil ; case-sensitive search by default
        ivy-count-format "(%d/%d) "
        ivy-height 10
        ;; Press C-p and Enter to select current input as candidate
        ;; https://oremacs.com/2017/11/30/ivy-0.10.0/
        ivy-use-selectable-prompt t
        ivy-use-virtual-buffers t
        )
  (add-to-list 'ivy-re-builders-alist `(swiper . ivy--regex))
  (add-to-list 'ivy-re-builders-alist `(swiper-all . ivy--regex))
  (add-to-list 'ivy-re-builders-alist `(read-file-name-internal . ivy--regex-fuzzy))
  )
(after! evil
  (setq which-key-min-display-lines 15
        ; https://github.com/doomemacs/doomemacs/issues/5622#issuecomment-946760888
        which-key-allow-imprecise-window-fit nil
        )
  ;(general-define-key "C-s" '(counsel-grep-or-swiper :which-key "search"))
  ;(general-define-key :keymaps '(swiper-map) "C-u" '(lambda () (interactive) (kill-line 0)))
  ;(general-nvmap "/" '(counsel-grep-or-swiper :which-key "search in buffer"))
  (evil-define-key 'normal global-map
                   (kbd "/") 'swiper
                   (kbd "C-f") 'swiper-all
                   (kbd "C-/") 'swiper-all/search-word-at-point
                   (kbd "*") 'search-word-at-point
                   (kbd "g*") 'search-unbounded-word-at-point
                   )
  )

;; Editing
(after! evil
  (setq evil-want-fine-undo t
        )
  (customize-set-variable 'evil-want-Y-yank-to-eol nil)
  (evil-define-key 'normal global-map (kbd "K") 'evil-join)
  (evil-define-key 'insert global-map (kbd "C-u") '(lambda () (interactive) (kill-line 0)))
  (evil-define-key 'normal global-map (kbd "SPC g d") 'git-gutter:popup-hunk)
  )
(setq +vc-gutter-default-style nil
      )
(customize-set-variable 'git-gutter:update-interval 2)
;(customize-set-variable 'git-gutter:window-width 2)
(after! git-gutter-fringe
  (require 'fringe-helper)
  ; Narrower vertical bar, matching the one in the "+" of git-gutter-fr:added
  (fringe-helper-define 'git-gutter-fr:modified nil
                        "...XX..."
                        "...XX..."
                        ".XXXXXX."
                        ".XXXXXX."
                        "...XX..."
                        "...XX..."
                        ".XXXXXX."
                        ".XXXXXX.")
  ; Narrower horizontql bar, matching the one in the "+" of git-gutter-fr:added
  (fringe-helper-define 'git-gutter-fr:deleted nil
                        "........"
                        "........"
                        "........"
                        ".XXXXXX."
                        ".XXXXXX."
                        "........"
                        "........"
                        "........")
  )


;; Folding
(defun set-selective-display/at-point (&optional level)
  "Fold text indented same of more than the cursor.
  If level is set, set the indent level to LEVEL.
  If 'selective-display' is already set to LEVEL,
  calling it again will unset 'selective-display' by setting it to 0."
    (interactive "P")
    (if (eq selective-display (1+ (current-column)))
        (set-selective-display 0)
        (set-selective-display (or level (1+ (current-column))))))
(after! evil
  (evil-define-key 'normal global-map
                   (kbd "C-d") 'set-selective-display/at-point)
  )

;; Navigating
;; DOC: https://github.com/noctuid/evil-guide
(after! evil
  (setq evil-cross-lines t
        evil-ex-search-case 'sensitive
        evil-move-cursor-back nil
        evil-search-wrap nil
        evil-want-C-i-jump nil
        )

  ;; Switching buffers
  (evil-define-key 'motion 'global
                   (kbd "<C-i>") 'evil-prev-buffer ; Does not work without the angles ('<' and '>')
                   (kbd "C-k") 'evil-next-buffer
                   (kbd "C-x k") 'kill-current-buffer
                   (kbd "C-m") 'counsel-switch-buffer
                   )
  ;(define-key evil-normal-state-map [tab] 'evil-prev-buffer)

  ;; Jumping
  (evil-define-key 'motion 'global
                   (kbd "C-u") 'better-jumper-jump-backward
                   (kbd "C-o") 'better-jumper-jump-forward
                   )
  ;; Jumping
  ;(evil-define-key '(motion normal visual) 'global
                    ;(kbd "C--") 'doom/decrease-font-size
                    ;(kbd "C-=") 'doom/increase-font-size
  ;                 )

  ;; Moving with ijkl (instead of hjkl)
  (evil-define-key '(motion normal visual) 'global
                   (kbd "i") 'evil-previous-visual-line
                   (kbd "j") 'evil-backward-char
                   (kbd "k") 'evil-next-visual-line
                   (kbd "h") 'evil-insert
                   )

  ;; Switching windows with SPC-w + ijkl (instead of hjkl)
  (define-key evil-window-map "i" 'evil-window-up)
  (define-key evil-window-map "I" 'evil-window-move-very-top)
  (define-key evil-window-map "j" 'evil-window-left)
  (define-key evil-window-map "J" 'evil-window-move-far-left)
  (define-key evil-window-map "k" 'evil-window-down)
  (define-key evil-window-map "K" 'evil-window-move-very-bottom)
  ;(define-key evil-emacs-state-map "\C-w" 'evil-window-map)
  ;;(evil-define-key 'window global-map "l" 'evil-window-right)
  ;;(evil-define-key 'window global-map "L" 'evil-window-move-far-right)

  ;; ijkl in Dired
  ;;(evil-define-key 'normal dired-mode-map "i" 'evil-previous-line)

  ;; Errors
  (evil-define-key 'motion 'global
                   (kbd "C-j") 'previous-error
                   (kbd "C-l") 'next-error
                   )
  ;(bind-key "C-j" #'previous-error)
  ;(bind-key "C-l" #'next-error)
  )
(after! auto-yasnippet
  (evil-define-key '(motion normal) 'global
                   (kbd "C-<tab>") 'evil-switch-to-windows-last-buffer
                   )
  )
(after! (evil magit evil-collection-magit)
  (evil-define-key '(motion normal) magit-mode-map
                   (kbd "C-i") 'evil-prev-buffer
                   (kbd "i") 'evil-previous-visual-line
                   (kbd "k") 'evil-next-visual-line
                   (kbd "C-k") 'evil-next-buffer
                   (kbd "j") 'magit-section-backward
                   (kbd "l") 'magit-section-forward
                   )
  )
(after! (evil magit git-rebase)
  (evil-define-key '(motion normal) git-rebase-mode-map
                   (kbd "C-i") 'evil-prev-buffer
                   (kbd "i") 'evil-previous-visual-line
                   (kbd "k") 'evil-next-visual-line
                   (kbd "C-k") 'evil-next-buffer
                   (kbd "j") 'evil-backward-char
                   )
  )
;;(eval-after-load 'evil ; to run after evil-integration.el
;;  '(progn
;;   (define-key Buffer-menu-mode-map     "\C-i" 'evil-prev-buffer)
;;   (define-key Buffer-menu-mode-map     "\C-k" 'evil-next-buffer)
;;   (define-key messages-buffer-mode-map "\C-i" 'evil-prev-buffer)
;;   (define-key messages-buffer-mode-map "\C-k" 'evil-next-buffer)
;;   (define-key completion-list-mode-map "\C-i" 'evil-prev-buffer)
;;   (define-key completion-list-mode-map "\C-k" 'evil-next-buffer)
;;   ;(define-key custom-theme-mode-map    "\C-i" 'evil-prev-buffer)
;;   ;(define-key custom-theme-mode-map    "\C-k" 'evil-next-buffer)
;;   )
;;  )

;;(with-eval-after-load 'evil-maps
;;  (define-key evil-motion-state-map (kbd "TAB") nil))

;; Feed reader
; See also: Managing ArXiv RSS Feeds in Emacs https://cundy.me/post/elfeed/

(setq
  elfeed-enable-web-interface t
  url-queue-timeout 30
  )
;(global-set-key (kbd "C-x w") 'elfeed)

(defun elfeed-mark-all-as-read ()
  (interactive)
  (mark-whole-buffer)
  (elfeed-search-untag-all-unread))

; Functions to support syncing .elfeed between machines
; makes sure elfeed reads index from disk before launching
(defun elfeed-load-db-and-open ()
  "Wrapper to load the elfeed db from disk before opening"
  (interactive)
  (elfeed-db-load)
  (elfeed)
  (elfeed-search-update--force))

; Write to disk when quiting
(defun elfeed-save-db-and-bury ()
  "Wrapper to save the elfeed db to disk before burying buffer"
  (interactive)
  (elfeed-db-save)
  (quit-window))

(defun elfeed-toggle-star ()
  "Toggle star"
  (interactive)
  (elfeed-search-tag-all '*)
  )
(after! (evil elfeed evil-collection-elfeed)
  (evil-define-key 'motion elfeed-search-mode-map "m" #'elfeed-toggle-star)
  )

(defun elfeed-org-update-incremental ()
  "Automatically update the feeds from feeds.org when updated"
   (setq my-elfeed-org-last (or (and (boundp 'elfeed-feeds) elfeed-feeds) nil))
  (elfeed)
  (setq my-elfeed-org-current elfeed-feeds)
  (let ((elfeed-feeds (-difference my-elfeed-org-current my-elfeed-org-last)))
    ;; You don't need the line below if you don't want to see a message about what feeds are being updated
    (message "%s"  elfeed-feeds)
    (mapc #'elfeed-update-feed (elfeed--shuffle (elfeed-feed-list))))
  (setq elfeed-feeds my-elfeed-org-current))