;;; package --- Summary
;;; Commentary:
;;; Code:
;;; Package management
;;;; Package

(require 'package)                                                              ; Use 'package
(setq package-archives '(("melpa" . "https://melpa.org/packages/")
                         ("non-gnu" . "https://elpa.nongnu.org/nongnu/")
                         ("gnu"   . "https://elpa.gnu.org/packages/")))
(setq package-enable-at-startup nil)                                            ; Enable package at startup
(package-initialize)                                                            ; And initialize

;;;; Use-package

(prefer-coding-system       'utf-8)
(setq-default                                                                   ; Set options for use-package :
 use-package-always-ensure t                                                    ; - always ensure (use :ensure nil for built-in packages)
 use-package-expand-minimally t
 use-package-verbose nil
 use-package-enable-imenu-support t)                                            ; Enable navigating between packages with imenu

(unless (package-installed-p 'use-package)                                      ; Bootstrap use-package
  (package-refresh-contents)
  (package-install 'use-package))
(eval-when-compile (require 'use-package))

;;;; Quelpa

(use-package quelpa)

;;; Custom and options
;;;; Custom file

(setq custom-file "~/.config/emacs/custom.el")
(load custom-file)

;;;; Options

;;;;; Truncate lines

(setq-default truncate-lines t)                                                 ; Truncate lines by default in all buffers

;;;;; Mode-line

(setq
 eol-mnemonic-unix "(Unix)"                                                     ; Mnemonics for eol
 size-indication-mode t                                                         ; Display total size of buffer and column index
 column-number-mode t                                                           ; Column numbers
 column-number-indicator-zero-based nil)                                        ; Column numbers from 1

;;;;; Backup

(setq
 delete-old-versions t                                                          ; delete excess backup versions silently
 make-backup-files nil                                                          ; make backup files
 version-control nil                                                            ; Use version control on backups
 vc-make-backup-files nil                                                       ; don't make backups file when in version controlled dir
 backup-directory-alist nil)

;;;;; Autosave

(setq
 auto-save-default nil                                                          ; Enable
 auto-save-interval 300                                                         ; Set interval and timeout
 auto-save-timeout 30
 auto-save-file-name-transforms nil)                                            ; Set directory for auto-saves

;;;;; Scrolling

(setq
 scroll-margin 10                                                               ; Pad scrolling with 10 lines vertically
 hscroll-margin 10                                                              ; and horizontally
 scroll-conservatively 100000                                                   ; Sane defaults for a smooth scrolling experience
 scroll-preserve-screen-position 1
 hscroll-step 1
 maximum-scroll-margin 0.5)

;;;;; Disable GUI

(menu-bar-mode -1)                                                              ; Disable all gui elements
(tool-bar-mode -1)
(scroll-bar-mode -1)
(blink-cursor-mode -1)
(tooltip-mode -1)


(setq                                                                           ; Disable startup stuff
 inhibit-startup-screen t
 inhibit-startup-message t
 inhibit-startup-echo-area-message t)

;;;;; UTF8

(setq                                                                           ; Use UTF8 for everything
 coding-system-for-read    'utf-8
 coding-system-for-write   'utf-8)

(prefer-coding-system       'utf-8)
(set-default-coding-systems 'utf-8)
(set-terminal-coding-system 'utf-8)
(set-keyboard-coding-system 'utf-8)

;;;;; Open new windows vertically

(setq split-height-threshold 20
      split-width-threshold 80)                                                 ; with a minimal horizontal size of 80 chars

;; And define an alternate version of split-window-sensibly that tries first to split horizontally then vertically
(defun maxx/split-window-sensibly (&optional window)
  "Apply the same rules as split-window-sensibly to WINDOW, but try first to split horizontally then vertically.
Use split-{height,width}-threshold to decide which size to give a new window."
  (let ((window (or window (selected-window))))
    (or (and (window-splittable-p window t)
             ;; Split window horizontally.
             (with-selected-window window
               (split-window-right split-width-threshold)))
        (and (window-splittable-p window)
             ;; Split window vertically.
             (with-selected-window window
               (split-window-below split-height-threshold)))
        (and
         ;; If WINDOW is the only usable window on its frame (it is
         ;; the only one or, not being the only one, all the other
         ;; ones are dedicated) and is not the minibuffer window, try
         ;; to split it horizontally disregarding the value of
         ;; `split-height-threshold'.
         (let ((frame (window-frame window)))
           (or
            (eq window (frame-root-window frame))
            (catch 'done
              (walk-window-tree (lambda (w)
                                  (unless (or (eq w window)
                                              (window-dedicated-p w))
                                    (throw 'done nil)))
                                frame)
              t)))
         (not (window-minibuffer-p window))
         (let ((split-height-threshold 0))
           (when (window-splittable-p window)
             (with-selected-window window
               (split-window-right))))))))

(setq split-window-preferred-function 'maxx/split-window-sensibly)

;;;;; Set proxy at work

(when (equal (system-name) "hegp")                                              ; Set proxy settings when at work
  (setq url-proxy-services '(("no_proxy" . "127.0.0.1")
                             ("http" . "proxym-inter.aphp.fr:8080")
                             ("https" . "proxym-inter.aphp.fr:8080"))))

;;;;; Misc

(require 'iso-transl)                                                           ; Fix dead_circumflex with ibus

(put 'narrow-to-region 'disabled nil)                                           ; Stop warning when using narrow and dired
(put 'dired-find-alternate-file 'disabled nil)

(setq
 initial-scratch-message ""
 debugger-bury-or-kill 'kill                                                    ; Kill debug windows after use
 mouse-wheel-scroll-amount '(1 ((shift) . 1) ((control) . 1))                   ; Scroll smoothly with mouse
 standard-indent 2                                                              ; Indent two spaces
 vc-handled-backends ()                                                         ; disable VC
 vc-follow-symlinks t                                                           ; don't ask for confirmation when opening symlinked file
 vc-ignore-dir-regexp (format "\\(%s\\)\\|\\(%s\\)"                             ; disable vc for tramp files
                              vc-ignore-dir-regexp
                              tramp-file-name-regexp)
 ring-bell-function 'ignore                                                     ; silent bell when you make a mistake
 user-full-name "Maxime Wack"                                                   ; Identity
 gc-cons-threshold 50000000                                                     ; GC and file size limits
 large-file-warning-threshold 100000000
 frame-title-format                                                             ; Filename in title
 '((:eval (concat (if (buffer-file-name)
                      (abbreviate-file-name (buffer-file-name))
                    "%b") " (" server-name ")"))))

(setq-default
 indicate-empty-lines t                                                         ; Show empty lines at the end of the buffer
 tab-width 2                                                                    ; Spaces for indent
 indent-tabs-mode nil)                                                          ; Don't use tabs in indentation

(set-frame-parameter (selected-frame) 'alpha '(85 . 95))                        ; Set alpha

(unless (equal (system-name) "hegp")                                            ; Set font
  (set-frame-font "Fira Code 10" nil t))

(add-to-list 'default-frame-alist '(font . "Fira Code 10"))
                                                                                ; Set font and alpha for GUI
(add-to-list 'default-frame-alist '(alpha . (85 . 95)))

(fset 'yes-or-no-p 'y-or-n-p)                                                   ; Replace yes/no questions with y/n

(defun package--save-selected-packages (&rest opt)                               ; Disable tracking of installed packages
  "Disable package-selected-packages.
OPT is the optional arg to the original function"
  nil)

;;; Packages
;;;; Keys
;;;;; General

(defun maxx/kill-unmodified-buffers ()
  "Kill all the unmodified buffers."
  (interactive)
  (seq-do 'kill-buffer
          (seq-filter (lambda (x) (not (buffer-modified-p x))) (buffer-list))))

(use-package general
  :demand

  :config
  (general-create-definer spcleader
    :states '(normal visual insert emacs)
    :prefix "SPC"
    :non-normal-prefix "M-SPC")

  (spcleader                                                                    ; Misc spcleader bindings
    "RET" 'eval-defun
    "|"   'shell-command-on-region
    "."   'eval-expression
    "$"   '((lambda () (interactive) (find-file "~/Projects/dotfiles/.config/emacs/init.el")) :which-key "open config")
    "#"   '((lambda () (interactive) (load-file "~/Projects/dotfiles/.config/emacs/init.el")) :which-key "reload config")
    "l"   'reposition-window
    "W"   '(count-words-region :which-key "word count")
    "w"   'visual-line-mode)

  (spcleader                                                                    ; Killing buffers
    "k"   '((lambda () (interactive) (persp-kill-buffer (current-buffer))) :which-key "kill buffer")
    "K"   '(:ignore t :which-key "Kill buffers")
    "Kk"  'kill-some-buffers
    "Km"  '(maxx/kill-unmodified-buffers :which-key "Kill unmodified buffers")
    "Kp"  'persp-kill)

  (spcleader                                                                    ; Narrow
    "n"  '(:ignore t :which-key "Narrow")
    "nr" 'narrow-to-region
    "np" 'narrow-to-page
    "nf" 'narrow-to-defun
    "nc" 'polymode-toggle-chunk-narrowing
    "nw" 'widen)

  (spcleader                                                                    ; Direct access to modes
    "m" '(:ignore t :which-key "Modes")
    "mo" 'org-mode
    "mm" 'mu4e
    "me" 'eshell
    "mC" 'calc
    "mc" 'cfw:open-org-calendar
    "mr" 'ess-r-mode
    "mw" 'woman
    "mtv" 'seriestracker
    "map" 'osm-home
    "mf" 'elfeed))

;;;;; Hydra

(use-package hydra)

;;;;; Evil
;;;;;; Evil

(use-package evil
  :demand
  :after hydra

  :init
  (evil-mode t)

  :config
  (define-key global-map (kbd "<S-delete>") nil)

  (setq evil-want-integration nil
        evil-want-keybinding nil
        evil-want-Y-yank-to-eol t

        evil-emacs-state-cursor    '("red" box)                                 ; Colored cursors based on evil-state
        evil-normal-state-cursor   '("green" box)
        evil-visual-state-cursor   '("orange" box)
        evil-insert-state-cursor   '("red" bar)
        evil-replace-state-cursor  '("red" bar)
        evil-operator-state-cursor '("red" hollow)

        evil-default-state 'normal                                              ; use NORMAL mode/state EVERYWHERE by default
        evil-motion-state-modes nil
        evil-normal-state-modes nil
        evil-insert-state-modes nil
        evil-emacs-state-modes nil

        evil-overriding-maps nil                                                ; and don't let modes override the INSERT state (!)
        evil-intercept-maps nil

        evil-move-beyond-eol nil                                                ; don't move beyond eol

        evil-auto-balance-windows nil                                           ; do not auto balance windows
        evil-vsplit-window-right nil                                            ; split vertically to the left (as the column argument
                                                                                ; in evil-window-vsplit is for the size of the *new* window
        )

  (defalias 'w 'save-buffer)                                                    ; Set alias w/W to save-buffer (to continue using :w to save)
  (defalias 'W 'save-buffer)

  (defhydra hydra-window (:color red :timeout .3)                               ; Define a hydra for working with windows
    "Windows"
    ("t" evil-window-left)
    ("T" evil-window-move-far-left)
    ("s" evil-window-down)
    ("S" evil-window-move-very-bottom)
    ("d" evil-window-up)
    ("D" evil-window-move-very-top)
    ("r" evil-window-right)
    ("R" evil-window-move-far-right)
    ("+" (evil-window-increase-height 4))
    ("-" (evil-window-decrease-height 4))
    ("/" (evil-window-decrease-width 4))
    ("*" (evil-window-increase-width 4))
    ("=" (balance-windows))
    ("h" evil-window-split)
    ("v" (lambda () (interactive)
           (evil-window-vsplit 80)))
    ("c" evil-window-delete)
    ("o" delete-other-windows)
    ("é" nil "Cancel"))

  :general
  (:states 'visual
   "l"     'evil-delete
   "H"     'evil-change
   "J"     'evil-join
   "u"     'undo)

  (:states '(visual normal motion emacs)
   "é"     'hydra-window/body)

  (:states '(normal motion)                                                     ; Bépo rebindings
   "t"     'evil-backward-char
   "s"     'evil-next-visual-line
   "d"     'evil-previous-visual-line
   "r"     'evil-forward-char
   "gs"    'evil-next-line
   "gd"    'evil-previous-line
   "C-s"   'evil-scroll-line-down
   "C-d"   'evil-scroll-line-up
   "T"     'evil-window-top
   "S"     'evil-scroll-down
   "D"     'evil-scroll-up
   "l"     'evil-delete
   "L"     'evil-delete-line
   "n"     'evil-search-previous
   "N"     'evil-search-next
   "h"     'evil-replace
   "H"     'evil-replace-state
   "R"     'evil-window-bottom
   "M"     'evil-window-middle
   "j"     'evil-find-char-to
   ";"     'evil-repeat-find-char-reverse                                       ; Swap , and ;
   ","     'evil-repeat-find-char
   "q"     '(lambda () (interactive)                                                 ; Quit normal windows with q
              (condition-case nil
                  (delete-window)
                (error (quit-window))))
   "Q"     'evil-record-macro
   "u"     'undo-tree-undo                                                      ; Undo/redo with u/U and undo-tree
   "U"     'undo-tree-redo
   "/"     'counsel-grep-or-swiper
   "÷"     'evil-ex                                                             ; Access ex commands with ÷
   "zt"    'evil-close-fold                                                     ; Folding
   "zT"    'evil-close-folds
   "zr"    'evil-open-fold
   "zR"    'evil-open-folds
   "za"    '((lambda () (interactive)
               (hs-life-goes-on
                (if (hs-already-hidden-p)
                    (progn
                      (hs-show-block)
                      (hs-hide-level 1))
                  (hs-hide-block))))
             :which-key "toggle fold one level")
   "zA"    'evil-toggle-fold
   "gt"    'previous-buffer                                                     ; Buffers like tabs
   "gr"    'next-buffer
   "gf"    'evil-find-file-at-point-with-line
   "C-o"   'evil-jump-backward
   "C-ð"   '(lambda () (interactive) (scroll-other-window -1))                       ; Scroll other window with C-Ralt
   "C-ß"   '(lambda () (interactive) (scroll-other-window 1))
   "$"     'evil-end-of-visual-line
   "g$"    'evil-end-of-line
   "^"     'evil-first-non-blank-of-visual-line
   "g^"    'evil-first-non-blank)

  (:states 'insert
   "C-r"   'counsel-yank-pop
   "C-u"   'counsel-unicode-char
   "_"     'self-insert-command
   "<S-delete>" nil))

;;;;;; Evil-numbers

(use-package evil-numbers
  :general
  (:states '(normal motion)
   "+"     'evil-numbers/inc-at-pt
   "-"     'evil-numbers/dec-at-pt))

;;;;;; Evil-escape

(use-package evil-escape
  :init
  (evil-escape-mode t)

  :config
  (setq-default evil-escape-key-sequence "ii"
                evil-escape-delay 0.2))

;;;;;; Evil-commentary

(use-package evil-commentary
  :demand

  :init
  (evil-commentary-mode t)

  :config                                                                       ; Enable end-of-line comments
  (setq comment-inline-offset 5
        comment-auto-fill-only-comments t)
  (setq-default comment-column 80
                comment-fill-column nil
                fill-column 120)

  (defhydra hydra-comment (:color red :exit t)                                  ; Hydra to access comment commands
    "Comments"
    ("c" comment-indent)
    ("k" comment-kill))

  :general
  (:states 'normal
   "gcc"   'evil-commentary-line)

  (:states 'insert
   "M-RET" 'indent-new-comment-line                                             ; Continue comment on next line and add a line
   "M-j"   '(lambda () (interactive)                                                 ; Continue comment on next line without adding a new line
              (evil-next-line)
              (comment-indent)))

  (spcleader
    "c"     'hydra-comment/body)

  :hook (prog-mode . (lambda () (setq-local comment-column 80)                       ; Set column and function in all prog modes to 80
                       (setq-local comment-indent-function 'comment-indent-default)
                       (turn-on-auto-fill))))

;;;;;; Evil-surround

(use-package evil-surround
  :init
  (global-evil-surround-mode)

  :config
  (setq-default evil-surround-pairs-alist                                       ; Redefined to stop inserting extraneous spaces
               '((40 "(" . ")")
                 (91 "[" . "]")
                 (?{ "{" . "}")
                 (?< "<" . ">")
                 (?- "-" . "-")
                 (?_ "_" . "_")
                 (?t . evil-surround-read-tag)
                 (?f . evil-surround-function))))

;;;;;; Evil-lion

(use-package evil-lion
  :general
  (spcleader
    "a" 'evil-lion-left
    "A" 'evil-lion-right))

;;;;;; Evil-args

(use-package evil-args
  :general
  (:keymaps 'prog-mode-map
   :states  'normal
   "þ"      'evil-backward-arg
   "®"      'evil-forward-arg))

;;;;;; Text objects

(defmacro define-and-bind-text-object (key start-regex end-regex)               ; Macro to help define new text objects
  "Macro to help define and bind text objects.
Bind KEY to a text-object defined by the region surrounded by START-REGEX and END-REGEX."

    (let ((inner-name (make-symbol "inner-name"))
          (outer-name (make-symbol "outer-name")))
      `(progn
         (evil-define-text-object ,inner-name (count &optional beg end type)
           (evil-select-paren ,start-regex ,end-regex beg end type count nil))
         (evil-define-text-object ,outer-name (count &optional beg end type)
           (evil-select-paren ,start-regex ,end-regex beg end type count t))
         (define-key evil-inner-text-objects-map ,key (quote ,inner-name))
         (define-key evil-outer-text-objects-map ,key (quote ,outer-name)))))

(define-and-bind-text-object "_" "_" "_")                                       ; Text objects for common separators
(define-and-bind-text-object "-" "-" "-")
(define-and-bind-text-object "," "," ",")
(define-and-bind-text-object ";" ";" ";")
(define-and-bind-text-object "/" "/" "/")
(define-and-bind-text-object "|" "|" "|")
(define-key evil-inner-text-objects-map "a" 'evil-inner-arg)
(define-key evil-outer-text-objects-map "a" 'evil-outer-arg)

;;;;; Which-key

(use-package which-key
  :init
  (which-key-mode t)

  :config
  (setq which-key-allow-evil-operators t))

;;;; Basics
;;;;; Built-in
;;;;;; Package

(use-package package                                                            ; Manage packages
  :general
  (:keymaps 'package-menu-mode-map
   :states  'normal
   "q"      'kill-buffer-and-window
   "x"      'package-menu-execute))

;;;;;; Custom

(use-package cus-edit                                                           ; Custom options
  :ensure nil

  :config
  (add-to-list 'evil-emacs-state-modes 'Custom-mode))                           ; Custom mode in emacs state

;;;;;; Ediff

(use-package ediff                                                              ; Diffs vertically
  :config
  (setq ediff-merge-split-window-function 'split-window-vertically
        ediff-window-setup-function 'ediff-setup-windows-plain)
  (add-to-list 'evil-emacs-state-modes 'ediff-mode))

;;;;;; Debugger

(use-package debug
  :demand

  :config
  (add-to-list 'display-buffer-alist '("^\\*Backtrace"
                                       (display-buffer-reuse-window display-buffer-in-side-window)
                                       (side . top)
                                       (window-height . 20)
                                       (reusable-frames . nil)))

  :general
  (:keymaps 'debugger-mode-map
   :states  'normal
   "ð"      'backtrace-backward-frame
   "ß"      'backtrace-forward-frame
   "þ"      'backtrace-single-line
   "®"      'backtrace-multi-line
   "SPC"    'debugger-step-through
   "c"      'debugger-continue
   "b"      'debugger-frame
   "u"      'debugger-frame-clear
   "q"      'debugger-quit
   "v"      'backtrace-toggle-locals
   "e"      'debugger-eval-expression)

  :hook (debugger-mode . (lambda ()
                          (setq buffer-face-mode-face '(:background "#301010"))
                          (buffer-face-mode 1))))

;;;;;; Edebug

(use-package edebug

  :general
  (:keymaps 'edebug-mode-map
   :states  'normal
   "SPC"    'edebug-step-mode
   "C"      'edebug-Continue-fast-mode
   "D"      'edebug-toggle-disable-breakpoint
   "G"      'edebug-Go-nonstop-mode
   "Q"      'edebug-top-level-nonstop
   "T"      'edebug-Trace-fast-mode
   "U"      'edebug-unset-breakpoints
   "W"      'edebug-toggle-save-windows
   "X"      'edebug-set-global-break-condition
   "a"      'recursive-edit
   "b"      'edebug-set-breakpoint
   "c"      'edebug-continue-mode
   "g"      'edebug-go-mode
   "q"      'top-level
   "t"      'edebug-trace-mode
   "u"      'edebug-unset-breakpoint
   "w"      'edebug-where
   "x"      'edebug-set-conditional-breakpoint)

  :hook (edebug-mode . (lambda ()
                         (setq buffer-face-mode-face '(:background "#301010"))
                         (if edebug-mode
                             (buffer-face-mode 1)
                           (buffer-face-mode -1)))))

;;;;;; Profiler

(use-package profiler

  :general
  (:keymaps 'profiler-report-mode-map
   :states 'normal
   "ß" 'profiler-report-next-entry
   "ð" 'profiler-report-previous-entry
   "®" 'profiler-report-toggle-entry
   "þ" 'profiler-report-toggle-entry))

;;;;;; Paren

(use-package paren                                                              ; Show parentheses
  :init
  (show-paren-mode t)

  :config
  (setq show-paren-delay 0))                                                    ; Show parentheses immediately

;;;;;; Flyspell

(use-package flyspell                                                            ; Spellcheck
  :general
  (spcleader
    "s"  '(:ignore t :which-key "Flyspell")
    "ss" 'flyspell-goto-next-error
    "sd" 'flyspell-check-previous-highlighted-word
    "sc" 'ispell-word
    "sf" '((lambda () (interactive) (ispell-change-dictionary "francais") (flyspell-buffer)) :which-key "Switch to French")
    "sa" '((lambda () (interactive) (ispell-change-dictionary "american") (flyspell-buffer)) :which-key "Switch to American"))

  (:states 'insert
   "C-s"   'flyspell-check-previous-highlighted-word)

  :hook (prog-mode . flyspell-prog-mode))                                        ; Spellcheck comments in programming modes

;;;;;; Tar-mode

(use-package tar-mode                                                           ; Open archives transparently
  :general
  (:keymaps 'tar-mode-map
   :states  'normal
   "RET"    'tar-extract-other-window))

;;;;;; Whitespace

(use-package whitespace                                                         ; Show whitespaces and clean them upon saving
  :config
  (setq whitespace-style
        '(face
          tabs
          spaces
          trailing
          empty
          space-mark
          tab-mark
          )))

;;;;;; Info

(use-package info                                                               ; Info mode
  :general
  (:keymaps 'Info-mode-map
   :states  'normal
   "ð"      'Info-backward-node
   "ß"      'Info-forward-node
   "Þ"      'Info-up
   "þ"      'Info-up
   "q"      'Info-exit
   "ẞ"      'Info-next
   "Ð"      'Info-prev
   "gr"     'Info-history-forward
   "gt"     'Info-history-back
   "gg"     'evil-goto-first-line
   "s"      'evil-next-visual-line
   "d"      'evil-previous-visual-line
   "RET"    'Info-follow-nearest-node))

;;;;;; Highlight line

(use-package hl-line                                                            ; Highlight current line
  :init
  (global-hl-line-mode t)

  :custom-face
  (hl-line ((t (:background "gray10")))))

;;;;;; Simple

(use-package simple                                                             ; Use correct italic font with Fira Code
  :ensure nil

  :custom-face
  (italic ((t (:family "Fira Code Italic"
               :foundry "Fira Code Italic")))))

;;;;;; Autorevert

(use-package autorevert                                                         ; Update files changed on disk automatically
  :init
  (global-auto-revert-mode t)

  :config
  (setq auto-revert-remote-files t))

;;;;;; Elisp

(use-package elisp-mode
  :ensure nil

  :config
  (setq eval-expression-print-length nil                                        ; No size limit for displaying objects
        eval-expression-print-level nil)                                        ; No depth limit for displaying lists

  :general
  (:keymaps 'emacs-lisp-mode-map
   :states  'normal
   "RET"    'eval-defun)

  (:keymaps 'emacs-lisp-mode-map
   :states  'insert
   [(control return)] 'eval-print-last-sexp)

  (:keymaps 'emacs-lisp-mode-map
   :states  'visual
   "RET"    '(lambda (start end)
               (interactive "r")
               (eval-region start end t))))

;;;;;; Help

(use-package help-mode
  :ensure nil

  :config
  (add-to-list 'display-buffer-alist '("*Help*"
                                       (display-buffer-reuse-window display-buffer-in-side-window)
                                       (side . left)
                                       (window-width . 80)
                                       (reusable-frames . nil)))

  :general
  (spcleader
    "h"  '(:ignore t :which-key "Help")
    "hh" 'help-for-help
    "ha" 'apropos-command
    "hb" 'counsel-descbinds
    "hv" 'counsel-describe-variable
    "hf" 'counsel-describe-function
    "ho" 'helpful-at-point
    "hm" 'describe-mode
    "hp" 'finder-by-keyword
    "hP" 'describe-package
    "hk" 'helpful-key
    "hK" 'Info-goto-emacs-key-command-node
    "hi" 'info
    "hF" 'counsel-faces
    "hc" 'counsel-colors-emacs
    "hL" 'describe-language-environment
    "hl" '((lambda () (interactive) (view-buffer-other-window "*Emacs Log*"))
           :which-key "View input logs"))

  (:keymaps 'help-mode-map
   :states  'normal
   "TAB"    'forward-button
   "q"      'kill-buffer-and-window
   "P"      'help-go-back
   "N"      'help-go-forward)

  :hook (help-mode . (lambda ()
                       (setq buffer-face-mode-face '(:background "#102030"))
                       (buffer-face-mode 1))))

;;;;;; Markdown

(use-package markdown-mode
  :config
  (setq markdown-asymmetric-header t)

  :custom-face
  (markdown-header-face-1 ((t (:inherit 'outline-1))))
  (markdown-header-face-2 ((t (:inherit 'outline-2))))
  (markdown-header-face-3 ((t (:inherit 'outline-3))))
  (markdown-header-face-4 ((t (:inherit 'outline-4))))
  (markdown-header-face-5 ((t (:inherit 'outline-5))))
  (markdown-bold-face ((t (:foreground "#ede0ce"))))
  (markdown-italic-face ((t (:foreground "#ede0ce"))))
  (markdown-header-delimiter-face ((t (:foreground "gray30")))))

;;;;;; Eshell

(defun maxx/eshell-keys ()
  "Eshell-mode-map is not populated outside of eshell.
So we need to define bindings in a hook."
  (evil-define-key*
   'insert
   eshell-mode-map
   "ð" 'eshell-previous-matching-input-from-input
   "ß" 'eshell-next-matching-input-from-input
   "þ" 'eshell-backward-argument
   "®" 'eshell-forward-argument
   "Þ" 'eshell-kill-input
   "Ð" 'eshell-previous-prompt
   "ẞ" 'eshell-next-prompt
   "C-l" 'eshell/clear)
  )

(use-package eshell
  :config
  (setq eshell-scroll-to-bottom-on-input t)
  (add-to-list 'evil-insert-state-modes 'eshell-mode)

  :hook (eshell-first-time-mode . maxx/eshell-keys))

;;;;;; Zoom

(use-package face-remap
  :config
  (defhydra hydra-zoom (:color red)
    "Zoom"
    ("+" text-scale-increase)
    ("-" text-scale-decrease)
    ("/" (text-scale-adjust 0) "Reset"))

  :general
  (:states 'normal
   "C-+"   'hydra-zoom/text-scale-increase
   "C--"   'hydra-zoom/text-scale-decrease))

;;;;;; Calc

(use-package calc
  :config
  (add-to-list 'evil-emacs-state-modes 'calc-mode))

;;;;;; Calendar

(use-package calendar
  :config
  (calendar-set-date-style 'iso)
  (defvar holiday-french-holidays
    '((holiday-fixed 1 1      "Jour de l'an")
      (holiday-fixed 1 6      "Épiphanie")
      (holiday-fixed 2 2      "Chandeleur")
      (holiday-fixed 2 14     "Saint Valentin")
      (holiday-fixed 5 1      "Fête du travail")
      (holiday-fixed 5 8      "Commémoration de la capitulation de l'Allemagne en 1945")
      (holiday-fixed 6 21     "Fête de la musique")
      (holiday-fixed 7 14     "Fête nationale - Prise de la Bastille")
      (holiday-fixed 8 15     "Assomption (Religieux)")
      (holiday-fixed 11 11    "Armistice de 1918")
      (holiday-fixed 11 1     "Toussaint")
      (holiday-fixed 11 2     "Commémoration des fidèles défunts")
      (holiday-fixed 12 25    "Noël")
      (holiday-easter-etc 0   "Pâques")                                         ; fetes a date variable
      (holiday-easter-etc 1   "Lundi de Pâques")
      (holiday-easter-etc 39  "Ascension")
      (holiday-easter-etc 49  "Pentecôte")
      (holiday-easter-etc 50  "Lundi de la Pentecôte")
      (holiday-easter-etc -47 "Mardi gras")
      (holiday-float 5 0 -1   "Fête des mères")
      (holiday-float 6 0 3    "Fête des pères")))

  (setq calendar-week-start-day 1
        calendar-holidays holiday-french-holidays
        calendar-mark-holidays-flag t
        calendar-mark-diary-entries-flag t
        calendar-view-diary-initially-flag t
        calendar-view-holidays-initially-flag t
        calendar-left-margin 4)

  (add-to-list 'display-buffer-alist '("^\\*Calendar\\*"
                                       (display-buffer-reuse-window display-buffer-in-side-window)
                                       (side . top)
                                       (window-height . 12)
                                       (reusable-frames . nil)))

  :general
  (:keymaps 'calendar-mode-map
   :states  'normal
   "q"      'calendar-exit
   "RET"    'diary-view-entries
   "ð"      'calendar-backward-week
   "ß"      'calendar-forward-week
   "þ"      'calendar-backward-day
   "®"      'calendar-forward-day
   "Þ"      '(lambda ()
               (interactive)
               (calendar-backward-month 1)
               (calendar-scroll-right))
   "™"      '(lambda ()
               (interactive)
               (calendar-forward-month 1)
               (calendar-scroll-left))
   "Ð"      'calendar-backward-year
   "ẞ"      'calendar-forward-year
   "T"      'calendar-goto-today
   "D"      'calendar-goto-date))

;;;;;; Diary

(use-package diary-lib
  :config
  (setq diary-number-of-entries 7
        diary-file "~/Projects/diary")
  (add-to-list 'display-buffer-alist '("\\*Holidays\\*"
                                       (display-buffer-reuse-window display-buffer-in-side-window)
                                       (side . top)
                                       (slot . 1)
                                       (window-height . 12)
                                       (reusable-frames . nil)))
  (add-to-list 'display-buffer-alist '("\\*Fancy Diary Entries\\*"
                                       (display-buffer-reuse-window display-buffer-in-side-window)
                                       (side . top)
                                       (slot . -1)
                                       (window-height . 12)
                                       (reusable-frames . nil)))

  :hook (diary-list-entries . diary-sort-entries)

  :custom-face
  (diary ((t (:foreground "black" :background "limegreen"))))
  (org-agenda-diary ((t (:foreground "DarkTurquoise")))))

;;;;;; Winner

(use-package winner                                                             ; Undo-redo window configuration
  :demand

  :init
  (winner-mode 1)

  :general
  ("C-c u" 'winner-undo
   "C-c U" 'winner-redo))

;;;;;; Dired

(use-package dired
  :ensure nil

  :config
  (setq wdired-allow-to-change-permissions t
        dired-dwim-target t)

  :general
  (:keymaps 'dired-mode-map
   :states  'normal
   "d"      'dired-previous-line
   "s"      'dired-next-line
   "S"      'dired-sort-toggle-or-edit
   "t"      'dired-up-directory
   "r"      'dired-find-alternate-file
   "m"      'dired-mark
   "RET"    'dired-find-alternate-file
   "X"      'dired-do-flagged-delete
   "x"      'dired-flag-file-deletion
   "W"      'wdired-change-to-wdired-mode
   "q"      'kill-buffer-and-window)

  :hook (dired-mode . all-the-icons-dired-mode))

;;;;;; Tramp

(use-package tramp
  :config
  (setq tramp-terminal-type "tramp"
        tramp-default-method "ssh"
        tramp-encoding-shell "/bin/bash"
        tramp-default-remote-shell "/bin/bash"
        tramp-connection-timeout 5))

;;;;;; Subword

(use-package subword                                                            ; Word commands understand camelCase
  :init
  (global-subword-mode))

;;;;;; Hideshow

(use-package hideshow                                                           ; Code folding
  :hook (prog-mode . hs-minor-mode))

;;;;;; Minibuffer

(use-package minibuffer
  :ensure nil

  :general
  (:keymaps 'read-expression-map
   "ð"      'previous-line-or-history-element
   "ß"      'next-line-or-history-element
   "<delete>" 'delete-char))

;;;;;; electric-pair

(use-package electric

  :config
  (electric-pair-mode))

;;;;; Auto-insert

(defun autoinsert-yas-expand ()
  "Replace text in yasnippet template."

  (yas-expand-snippet (buffer-string) (point-min) (point-max)))

(use-package autoinsert                                                         ; Auto insert content when creating a new file
  :init
  (auto-insert-mode)

  :config
  (setq auto-insert-directory (locate-user-emacs-file "templates"))

  (define-auto-insert "\\.Rmd$" ["template.Rmd" autoinsert-yas-expand])

  :hook (find-file . auto-insert))

;;;;; Undo-tree

(use-package undo-tree
  :demand

  :init
  (global-undo-tree-mode 1)

  :config
  (setq undo-tree-auto-save-history nil
        undo-tree-history-directory-alist nil
        undo-tree-enable-undo-in-region t)

  (add-to-list 'display-buffer-alist '("*undo-tree"                             ; Undo-tree is displayed in a side window
                                       (display-buffer-reuse-window display-buffer-in-side-window)
                                       (side . left)
                                       (window-width . 0.15)
                                       (reusable-frames . nil)))

  (defun undo-tree-visualizer-show-diff (&optional node)                        ; Redefine to use a side-window instead of splitting window,
    "Show visualizer diff display."                                             ; as a side-window can't be split further
    (setq undo-tree-visualizer-diff t)
    (let ((buff (with-current-buffer undo-tree-visualizer-parent-buffer
                  (undo-tree-diff node)))
          (display-buffer-mark-dedicated 'soft))
      (display-buffer-in-side-window buff '((side . left)
                                            (slot . 1)))))

  :general
  (spcleader "u" 'undo-tree-visualize)

  (:keymaps 'undo-tree-visualizer-mode-map
   :states  'normal
   "q"      'undo-tree-visualizer-quit
   "SPC u"  'undo-tree-visualizer-quit
   "d"      'undo-tree-visualize-undo
   "s"      'undo-tree-visualize-redo
   "D"      'undo-tree-visualizer-toggle-diff))

;;;;; Avy

(use-package avy                                                                ; Jump anywhere with <spc><spc>
  :config
  (setq avy-keys '(?t ?s ?r ?n)
        avy-background t
        avy-highlight-first t)

  :general
  (spcleader
    "SPC" '(avy-goto-char-timer :which-key "Avy"))

  :custom-face
  (avy-goto-char-timer-face ((t (:background nil :foreground "red2" :weight bold))))
  (avy-lead-face ((t (:background nil :foreground "red1"))))
  (avy-lead-face-0 ((t (:background nil :foreground "red4"))))
  (avy-lead-face-1 ((t (:background nil :foreground "red4"))))
  (avy-lead-face-2 ((t (:background nil :foreground "red4")))))


;;;;; Ace-link

(use-package ace-link                                                           ; Links shortcuts
  :general
  (:keymaps '(Info-mode-map
              help-mode-map
              helpful-mode-map
              org-mode-map)
   :states  'normal
   "f"      'ace-link)
   (:keymaps '(gnus-summary-mode-map
              mu4e-view-mode-map
              gnus-article-mode-map)
   :states  'normal
   "f"      'ace-link-gnus))

;;;;; All the icons

(use-package all-the-icons-ivy-rich
  :init
  (all-the-icons-ivy-rich-mode))

(use-package all-the-icons-dired
  :init
  (all-the-icons-dired-mode))

;;;;; Doom
;;;;;; Doom theme

(use-package doom-themes
  :config
  (load-theme 'doom-peacock t)
  (setq doom-themes-enable-bold t
        doom-themes-enable-italic t)
  (doom-themes-visual-bell-config))

;;;;;; Doom modeline

(use-package doom-modeline
  :config
  (setq doom-modeline-enable-word-count t
        doom-modeline-icon t)
  ;; first time run M-x all-the-icons-install-fonts

  :hook (after-init . doom-modeline-mode))

;;;;; Expand region

(use-package expand-region                                                      ; Expand/contract visually selected region
  :config
  (defhydra hydra-expand-region (:color red)
    "Expand-region"
    ("e" er/expand-region)
    ("E" er/contract-region))

  :general
  (spcleader
    "e" 'hydra-expand-region/er/expand-region
    "E" 'hydra-expand-region/er/contract-region))

;;;;; Minions

(use-package minions                                                            ; Hide minor modes from modeline
  :init
  (minions-mode t)

  :config
  (setq minions-mode-line-lighter ""))

;;;;; Helpful

(use-package helpful                                                            ; Featureful help mode
  :demand

  :config
  (setq counsel-describe-function-function 'helpful-callable                    ; Use helpful as backend for counsel describe
        counsel-describe-variable-function 'helpful-variable
        helpful-max-buffers 1)                                                  ; use only one buffer for help

  (add-to-list 'display-buffer-alist '("^\\*helpful"
                                       (display-buffer-reuse-window display-buffer-in-side-window)
                                       (side . left)
                                       (window-width . 80)
                                       (reusable-frames . nil)))

  :general
  (:keymaps 'helpful-mode-map
   :states  'normal
   "TAB"    'forward-button
   "q"      'kill-buffer-and-window)

  :hook (helpful-mode . (lambda ()
                          (setq buffer-face-mode-face '(:background "#102030"))
                          (buffer-face-mode 1)))

  :custom-face
  (helpful-heading ((t (:height 1.9)))))

;;;;; Fira Code

(use-package fira-code-mode                                                     ; Use Fira Code and ligatures
  ;; run fira-code-mode-install-fonts to install the font
  
  ;; Br = base-right, Bl = base-left, Bc = base-center
  ;; rule = (global-ref . new-ref)
  ;; where global-ref is a position on the already existing glyph
  ;; new-ref is the position within the glyph to insert
  ;; Here, a first space is composed with two more spaces
  ;; appending the base left of each space anchored to the base right of the whole glyph
  ;; Then the triangle is added at the base center
  :hook
  (prog-mode . (lambda ()
                 (push '("%>%"
                         ?\s
                         (Br . Bl) ?\s
                         (Br . Bl) ?\s
                         (Bc . Bl) 57653)
                       prettify-symbols-alist)
                 (fira-code-mode))))

;;;;; Rainbow mode

(use-package rainbow-mode                                                       ; Show colors
  :demand

  :init
  (rainbow-mode))

;;;;; Doc view

(use-package doc-view                                                           ; Display documents (pdf, docx, etc)
  :config
  (setq doc-view-continuous t
        doc-view-resolution 200)

  :general
  (:keymaps 'doc-view-mode-map
   :states  'normal
   "d"      'doc-view-previous-line-or-previous-page
   "s"      'doc-view-next-line-or-next-page
   "ð"      'doc-view-previous-page
   "ß"      'doc-view-next-page
   "gg"     'doc-view-first-page
   "G"      'doc-view-last-page
   "q"      'kill-buffer-and-window
   "+"      'doc-view-enlarge
   "-"      'doc-view-shrink))

;;;;; Image Mode

(use-package image                                                              ; Display images
  :ensure nil

  :config
  (setq image-animate-loop t)

  :general
  (:keymaps 'image-mode-map
   :states  'normal
   "d" '(lambda () (interactive) (image-scroll-down 1))
   "s" '(lambda () (interactive) (image-scroll-up 1))
   "t" '(lambda () (interactive) (image-scroll-right 1))
   "r" '(lambda () (interactive) (image-scroll-left 1))
   "+" 'image-increase-size
   "-" 'image-decrease-size
   "{" 'image-decrease-speed
   "}" 'image-increase-speed
   "," 'image-previous-frame
   "." 'image-next-frame
   "RET" 'image-toggle-animation
   "l" 'image-rotate
   "v" '(lambda () (interactive) (image-transform-set-rotation (- image-transform-rotation 90)))
   "q" 'kill-buffer-and-window))

;;;;; Woman

(use-package woman                                                              ; Man pages
  :general
  (:keymaps 'woman-mode-map
   :states 'normal
   "ß" 'Man-next-section
   "ð" 'Man-previous-section
   "q" 'kill-buffer-and-window))

;;;;; Literate Calc Mode

(use-package literate-calc-mode
  :config
  (defalias 'calcFunc-conv 'math-convert-units))

;;;;; Emacs log

(use-package interaction-log                                                    ; Log all emacs actions in *Emacs Log*
  :config
  (interaction-log-mode))

;;;;; Paredit

(use-package paredit                                                            ; Semantic navigation in lisp
  :general
  (:keymaps '(slime-parent-map emacs-lisp-mode-map)
   :states  'normal
   "®"      '(lambda () (interactive) (paredit-forward) (paredit-forward) (paredit-backward))
   "þ"      'paredit-backward
   "ð"      'paredit-backward-up
   "ß"      'paredit-forward-down)

  :hook (emacs-lisp-mode . paredit-mode)
        (slime-mode . paredit-mode))

;;;; Completion
;;;;; Ivy
;;;;;; Ivy

(use-package ivy
  :config
  (setf (alist-get 'counsel-describe-function ivy-initial-inputs-alist) ""      ; Start with empty regex for describe function and variable
        (alist-get 'org-refile ivy-initial-inputs-alist) ""
        (alist-get 'counsel-describe-variable ivy-initial-inputs-alist) ""
        (alist-get 'org-capture-refile ivy-initial-inputs-alist) "")

  (setq ivy-wrap t
        ivy-height 15
        ivy-use-virtual-buffers t
        ivy-count-format "(%d/%d) "
        ivy-extra-directories nil
        ivy-re-builders-alist '((t . ivy--regex-ignore-order))
        ivy-switch-buffer-faces-alist '((dired-mode . ivy-subdir))
        completing-read-function 'ivy-completing-read)                          ; Use ivy as completion everywhere

  :general
  (:keymaps '(ivy-mode-map ivy-minibuffer-map)
   "ð"      'ivy-previous-line
   "ß"      'ivy-next-line
   "C-ß"      '(lambda ()
               (interactive)
               (scroll-other-window 1))
   "C-ð"      '(lambda ()
               (interactive)
               (scroll-other-window -1))
   "®"      'ivy-partial-or-done
   "þ"      '(lambda ()
               (interactive)
               (kill-buffer (ivy-state-current ivy-last)))
   "†"      'maxx/counsel-describe
   "S-RET"  'ivy-call))

;;;;;; Counsel

(use-package smex                                                               ; Show recently called M-x commands on top
  :init
  (setq smex-history-length 15))

(use-package counsel
  :config
  (setq counsel-yank-pop-preselect-last t)

  :general
  (spcleader
    "i"   'counsel-imenu
    "f"   'counsel-find-file
    "b"   'switch-to-buffer
    "x"   'counsel-M-x
    "/"   'counsel-grep-or-swiper)

  ("M-x" 'counsel-M-x)

  (:states '(normal motion)
   ":"     'counsel-M-x))

(defun maxx/counsel-describe ()
  "Display help for object at point in counsel."

  (interactive)
  (let ((inhibit-message t)
        (object (intern (ivy-state-current ivy-last))))
    (describe-symbol object)))

;;;;;; Ivy-rich

(use-package ivy-rich
  :config
  (plist-put ivy-rich-display-transformers-list
             'counsel-switch-buffer
             '(:columns ((ivy-rich-candidate (:width 30))
                         (ivy-rich-switch-buffer-size (:width 7))
                         (ivy-rich-switch-buffer-indicators (:width 4 :face error :align right))
                         (ivy-rich-switch-buffer-major-mode (:width 12 :face warning))
                         (ivy-rich-switch-buffer-project (:width 15 :face success))
                         (ivy-rich-switch-buffer-path (:width (lambda (x) (ivy-rich-switch-buffer-shorten-path x (ivy-rich-minibuffer-width 0.3))))))
                        :predicate (lambda (cand) (get-buffer cand))))

  (ivy-rich-mode 1))

;;;;; Company

(use-package company
  :demand

  :init
  (global-company-mode t)

  :config
  (setq company-idle-delay 0
        tab-always-indent 'complete
        company-selection-wrap-around t
        company-dabbrev-downcase nil
        company-dabbrev-ignore-case nil
        company-dabbrev-code-ignore-case t
        company-tooltip-align-annotations t
        company-minimum-prefix-length 2
        company-backends '(company-capf
                           company-clang
                           company-elisp
                           company-lua
                           company-files
                           (company-dabbrev-code company-gtags company-etags company-keywords)))

  :general
  (:states 'insert
   "TAB"    'company-indent-or-complete-common)
  (:keymaps 'company-active-map
   "ß"      'company-select-next
   "ð"      'company-select-previous
   "Ð"      'company-previous-page
   "ẞ"      'company-next-page
   "þ"      'company-abort
   "®"      'company-complete
   "†"      'company-show-doc-buffer))

;;;;; YASnippet

(use-package yasnippet
  :init
  (yas-global-mode))

;;;; Org
;;;;; Org

(use-package org
  :demand

  :config
  (org-babel-do-load-languages                                                  ; Supported languages in babel
   'org-babel-load-languages
   '((python . t)
     (R . t)
     (emacs-lisp . t)
     (shell . t)
     (plantuml . t)))

  (setq org-catch-invisible-edits 'smart
        org-directory "~/Projects/org"                                          ; Folders
        org-local-agenda-files (--filter
                                (not (s-contains-p "archive" it))
                                (directory-files-recursively
                                 "~/Projects/org"
                                 "\.org$"
                                 nil
                                 (lambda (filename) (not (s-contains-p "archive" filename)))))
        org-agenda-files (if (ignore-errors (file-exists-p "/ssh:android@home:Org/anniv.org"))
                             (cons "/ssh:android@home:Org/anniv.org" (cons "/ssh:android@home:Org/calendar.org" org-local-agenda-files))
                           org-local-agenda-files)
        org-default-notes-file "~/Projects/org/notes.org"
        org-archive-location "::* Archived"
        org-attach-method 'mv                                                   ; Move Attachments
        org-attach-store-link-p t
        org-startup-folded 'content                                             ; Startup
        org-startup-with-inline-images t
        org-startup-indented t
        org-edit-src-content-indentation 0
        org-startup-truncated t
        org-hide-emphasis-markers t
        org-hide-block-startup nil
        org-use-sub-superscripts '{}                                            ; Org sub/superscript behavior
        org-export-with-sub-superscripts '{}
        org-pretty-entities t
        org-pretty-entities-include-sub-superscripts t
        org-M-RET-may-split-line nil                                            ; RET behavior
        org-return-follows-link nil
        org-image-actual-width nil
        ;; org-id-link-to-org-use-id t                                             ; Generate UUIDs for links when storing link
        org-html-checkbox-type 'unicode
        org-enforce-todo-checkbox-dependencies nil                              ; Make todos dependent
        org-checkbox-hierarchical-statistics nil                                ; Recursive checkbox statistics
        org-enforce-todo-dependencies t
        org-log-into-drawer t                                                   ; Log states
        org-hierarchical-todo-statistics nil                                    ; Recursive todo statistics
        org-todo-keywords '((sequence "SOMEDAY(s)" "TODO(t)" "WAITING(w@)" "|" "DONE(d!)" "CANCELED(c@)"))     ; Todo keywords
        org-todo-keyword-faces                                                  ; Colors for TODOS
        '(("TODO" . "red")
          ("WAITING" . "orange")
          ("CANCELED" . (:strike-through t :foreground "DimGrey" :weight bold)))
        org-export-with-toc nil                                                 ; Do not create a TOC
        org-export-with-section-numbers nil                                     ; Do not number sections
        org-export-preserve-breaks t                                            ; Respect line breaks in exports
        org-refile-targets '((nil :maxlevel . 9)                                ; REFILE
                             (org-agenda-files :maxlevel . 9))
        org-refile-use-outline-path 'full-file-path
        org-outline-path-complete-in-steps nil
        org-imenu-depth 4)                                                      ; Deeper org-imenu search

  ;;;;;; Capture templates
  (setq org-capture-templates
        '(("t" "todo"
           entry (file+headline org-default-notes-file "Tasks")
           "* TODO %^{todo}\n\n%?"
           :empty-lines 1
           :prepend t)
          ("n" "note"
           entry (file+headline org-default-notes-file "Notes")
           "* %^{title}\n\n%?"
           :empty-lines 1
           :prepend t)
          ("m" "reu"
                 entry (file "/ssh:android@home:Org/calendar.org")
                 "* %^{Meeting}\nSCHEDULED: %^t\n\n%?"
                 :empty-lines 1
                 :prepend t)
          ("pp" "CPP"
           entry (file+headline "~/Projects/org/CPP.org" "Séances")
           "* Séance %^T\n\n%a\n\n%c"
           :prepend t
           :unnarrowed t
           :empty-lines 1)))

  (add-to-list 'display-buffer-alist '("*Org Agenda*"                           ; Org windows
                                       (display-buffer-reuse-window display-buffer-in-side-window)
                                       (side . right)
                                       (window-width . 70)
                                       (reusable-frames . nil)))

  (defface org-checkbox-done-text                                               ; Strike-through for checked boxes
    '((t (:foreground "DimGrey" :strike-through t)))
    "Face for text of checked boxes")

  (font-lock-add-keywords
   'org-mode
   `(("^[ \t]*\\(?:[-+*]\\|[0-9]+[).]\\)[ \t]+\\(\\(?:\\[@\\(?:start:\\)?[0-9]+\\][ \t]*\\)?\\[\\(?:X\\|\\([0-9]+\\)/\\2\\)\\][^\n]*\n\\)"
      1 'org-checkbox-done-text prepend))
   'append)

  (if (equal (system-name) "hegp-laptop")                                       ; Use Zathura for PDFs and xournal on hegp-laptop
      (setq org-file-apps '((auto-mode . emacs)
                            ("\\.mm\\'" . default)
                            ("\\.x?html?\\'" . default)
                            ("\\.pdf\\'" . "xournalpp %s")
                            ("\\.odt\\'" . "libreoffice %s")
                            ("\\.docx\\'" . "libreoffice %s")
                            ("\\.doc\\'" . "libreoffice %s")))
    (setq org-file-apps '((auto-mode . emacs)
                          ("\\.mm\\'" . default)
                          ("\\.x?html?\\'" . default)
                          ("\\.pdf\\'" . "zathura %s")
                          ("\\.odt\\'" . "libreoffice %s")
                          ("\\.docx\\'" . "libreoffice %s")
                          ("\\.doc\\'" . "libreoffice %s"))))

  :general                                                                      ; Menu keybindings
  (spcleader
    "o"  '(:ignore t :which-key "Org")
    "oa" 'org-agenda
    "oA" 'org-store-agenda-views
    "oc" 'projectorg/counsel-org-capture
    "ol" 'org-insert-link
    "oL" 'org-store-link
    "oi" 'org-toggle-inline-images
    "oS" 'org-sort
    "o*" 'org-toggle-heading
    "o/" 'org-sparse-tree
    "o|" 'org-table-create-or-convert-from-region
    "oE" 'org-table-edit-field
    "oe" 'org-export-dispatch
    "o}" 'org-table-toggle-coordinate-overlays
    "o{" 'org-table-toggle-formula-debugger
    "o?" 'org-table-field-info
    "o=" 'org-table-eval-formula
    "oD" 'org-insert-drawer
    "ot" 'org-todo
    "op" 'org-set-property
    "oP" 'org-tree-slide-mode
    "oC" 'org-columns
    "of" 'org-footnote-action
    "oj" 'org-attach
    "ow" 'org-refile
    "oz" 'org-archive-subtree
    "o." 'org-time-stamp
    "os" 'org-schedule
    "od" 'org-deadline
    "o." 'org-time-stamp
    "ob" 'org-ref-helm-insert-cite-link
    "oK" 'org-agenda-exit
    "oB" 'org-insert-structure-template)

  (:keymaps  'org-mode-map                                                      ; Normal keybindings
   :states   'normal
   "RET"     'org-open-at-point
   "gt"      'org-mark-ring-goto
   "<tab>"   'org-cycle
   "S-<tab>" 'org-global-cycle
   "M-s"     'org-metadown
   "M-d"     'org-metaup
   "M-r"     'org-metaright
   "M-t"     'org-metaleft
   "M-S"     'org-shiftmetadown
   "M-D"     'org-shiftmetaup
   "M-R"     'org-shiftmetaright
   "M-T"     'org-shiftmetaleft
   "C-s"     'org-shiftdown
   "C-d"     'org-shiftup
   "C-r"     'org-shiftright
   "C-t"     'org-shiftleft
   "©"       'org-babel-next-src-block
   "ſ"       'org-babel-previous-src-block)

  (:keymaps 'org-mode-map                                                       ; Insert keybindings
   :states  '(normal insert)
   "Þ"      'outline-up-heading
   "Ð"      'outline-backward-same-level
   "ẞ"      'outline-forward-same-level
   "þ"      'outshine-kbd-M-<left>
   "®"      'outshine-kbd-M-<right>
   "ð"      'org-previous-visible-heading
   "ß"      'org-next-visible-heading
   "<C-return>"  'org-insert-heading-after-current
   "M-t"    'org-metaleft
   "M-r"    'org-metaright)

  :hook (org-mode . (lambda ()                                                       ; Pretty checkboxes
                      (push '("[ ]" . "☐") prettify-symbols-alist)
                      (push '("[X]" . "☑" ) prettify-symbols-alist)
                      (push '("[-]" . "☒" ) prettify-symbols-alist)
                      (setq-local prettify-symbols-unprettify-at-point 'right-edge)
                      (prettify-symbols-mode)))

  :custom-face
  (highlight ((t (:background nil :foreground nil :box (:line-width 2 :color "dim gray") :DistantForeground nil))))
  (outline-1 ((t (:height 1.9 :background nil))))
  (outline-2 ((t (:height 1.6))))
  (outline-3 ((t (:height 1.4))))
  (outline-4 ((t (:height 1.2))))
  (outline-5 ((t (:height 1.1)))))

(require 'org-tempo)

;;;;; Org Agenda

(defun maxx/org-agenda-sort-strategy (a b)
  "Sort todo based on which I want to see first.
A is compared to B."

  (when-let ((state-a (get-text-property 14 'todo-state a))
             (state-b (get-text-property 14 'todo-state b))
             (cmp (--map (cl-position-if (lambda (x)
                                           (equal x it))
                                         '("TODO" "WAITING" "SOMEDAY" "CANCELED" "DONE"))
                         (list state-a state-b))))
    (cond ((apply '> cmp) 1)
          ((apply '< cmp) -1)
          (t nil))))

(use-package org-agenda
  :ensure nil

  :config
  (setq
   org-agenda-dim-blocked-tasks 'invisible                                      ; Hide blocked todos from agenda
   org-agenda-window-setup 'current-window                                      ; Agenda window
   org-agenda-restore-windows-after-quit t
   org-agenda-span 10                                                           ; Agenda for 10 days from 1 day before
   org-agenda-start-day "-1d"
   org-agenda-include-diary t
   org-agenda-skip-unavailable-files t
   org-agenda-tags-column -78
   org-agenda-remove-tags t
   org-agenda-start-with-follow-mode t
   org-agenda-todo-ignore-scheduled 'all
   org-agenda-todo-ignore-deadlines 'near
   org-agenda-skip-scheduled-if-done t
   org-agenda-skip-deadline-if-done t
   org-agenda-skip-scheduled-if-deadline-is-shown 'repeated-after-deadline
   org-agenda-skip-timestamp-if-done t
   org-agenda-skip-deadline-prewarning-if-scheduled t
   org-agenda-cmp-user-defined 'maxx/org-agenda-sort-strategy
   org-agenda-time-grid '((daily today require-timed remove-match)
                          (0000 0600 1200 1800 2359)
                          "      "
                          "-------------------")
   org-agenda-scheduled-leaders '("Scheduled: "
                                  "+%2d d:     ")
   org-agenda-deadline-leaders  '("Deadline:  "
                                  "In %2d d:   "
                                  "%2d d ago:  ")
   org-agenda-sorting-strategy
   '((agenda time-up deadline-up priority-down)
     (todo user-defined-up priority-down)
     (tags priority-down category-keep)
     (search category-keep))
   org-agenda-custom-commands
   '(("n" "Agenda and TODOs"
      ((agenda "")
       (alltodo ""))
      ((org-enforce-todo-dependencies nil)
       (org-agenda-skip-function
          '(org-agenda-skip-entry-if 'regexp ":notes:"))))
     ("N" "Local agenda and TODOs"
      ((agenda "")
       (alltodo ""))
      ((org-agenda-files org-local-agenda-files)
       (org-agenda-skip-function
          '(org-agenda-skip-entry-if 'regexp ":notes:"))))
     ("x" "Agenda for export"                                                   ; Use org-store-agenda-views to automatically export this view
      ((agenda ""))
      ((org-agenda-start-day "+0d")
       (org-agenda-skip-function
          '(org-agenda-skip-entry-if 'regexp ":notes:"))))
     ("X" "Local agenda export for orgzly"
      ((agenda "" ))
      ((org-agenda-span 'month)
       (org-deadline-past-days 0)
       (org-agenda-remove-timeranges-from-blocks t)
       (org-agenda-files org-local-agenda-files))
      ("/ssh:android@home:Org_exported/exported.org"))
     ("M" "PS export for reMarkable"
      ((agenda ""))
      ((org-agenda-start-day "+0d")
       (org-enforce-todo-dependencies nil)
       (org-agenda-skip-function
        '(org-agenda-skip-entry-if 'regexp ":notes:")))
      ("/tmp/agenda_export.ps"))))

  :general                                                                      ; Agenda keybindings
  (:keymaps 'org-agenda-mode-map
   :states  '(normal)
   "q"      'org-agenda-quit
   "C-d"    'org-agenda-priority-up
   "C-s"    'org-agenda-priority-down
   "i"      'org-agenda-diary-entry
   "T"      'org-agenda-todo
   "ß"      'org-agenda-next-item
   "ð"      'org-agenda-previous-item
   "RET"    'org-agenda-goto
   "®"      'org-agenda-goto
   "_"      'org-agenda-cycle-show
   "C"      'org-agenda-columns
   "Ð"      'org-agenda-earlier
   "ẞ"      'org-agenda-later
   "u"      'org-agenda-redo-all
   "S"      'org-agenda-schedule
   "D"      'org-agenda-deadline))

;;;;; Org notifications

(use-package org-wild-notifier
  :config
  (setq alert-default-style 'libnotify)
  ;; (org-wild-notifier-mode)
  )

;;;;; Org-bullets

(use-package org-bullets
  :config
  (setq org-hide-leading-stars t)

  :hook (org-mode . org-bullets-mode))

;;;;; Org fancy priorities

(use-package org-fancy-priorities
  :config
  (setq org-priority-faces                                                      ; Set colors
        '((?A . "#ff5d38")
          (?B . "orange")
          (?C . "#98be65")))

  (setq org-fancy-priorities-list                                               ; Set chars
        '((?A . "⬆")
          (?B . "·")
          (?C . "⬇")))

  :hook (org-mode . org-fancy-priorities-mode))

;;;;; Outshine

(use-package outshine
  :config
  (outshine-define-key outshine-mode-map
    (kbd "þ")
    'outshine-hide-more
    (outline-on-heading-p))

  (outshine-define-key outshine-mode-map
    (kbd "®") 'outshine-show-more
    (outline-on-heading-p))

  (outshine-define-key outshine-mode-map
    (kbd "ð") 'outline-previous-visible-heading
    (outline-on-heading-p))

  (outshine-define-key outshine-mode-map
    (kbd "ß") 'outline-next-visible-heading
    (outline-on-heading-p))

  :general
  (:keymaps  'outshine-mode-map
   :states   'normal
   "<tab>"   'outshine-cycle
   "S-<tab>" 'outshine-cycle-buffer
   [(control return)] 'outshine-insert-heading
   "ð"       'outshine-kbd-ð
   "ß"       'outshine-kbd-ß
   "Ð"       'outline-backward-same-level
   "ẞ"       'outline-forward-same-level
   "Þ"       'outline-up-heading
   "þ"       'outshine-kbd-þ
   "®"       'outshine-kbd-®
   "M-t"     'outshine-kbd-M-S-<left>
   "M-r"     'outshine-kbd-M-S-<right>
   "M-d"     'outshine-kbd-M-S-<up>
   "M-s"     'outshine-kbd-M-S-<down>)

  :hook (emacs-lisp-mode . outshine-mode))

;;;;; Org-ref

(use-package org-ref
  :config
  (setq org-ref-bibliography-notes "~/Projects/org/bib_notes.org"
        org-ref-pdf-directory "~/Projects/org/biblio/PDFs/"
        org-ref-completion-library 'org-ref-ivy-cite
        org-latex-pdf-process
        '("pdflatex -interaction nonstopmode -output-directory %o %f"
          "bibtex %b"
          "pdflatex -interaction nonstopmode -output-directory %o %f"
          "pdflatex -interaction nonstopmode -output-directory %o %f"))

        ;; org-latex-pdf-process '("latexmk -shell-escape -bibtex -f -pdf %f"))

  :general
  (:keymaps 'helm-map
   "ð"      'helm-previous-line
   "ß"      'helm-next-line)
  (:keymaps 'bibtex-mode-map
   "ð"      'org-ref-bibtex-previous-entry
   "ß"      'org-ref-bibtex-next-entry)
  (:keymaps 'bibtex-mode-map
   :states  'normal
   "RET"    'org-ref-bibtex-hydra/body))


;;;;; Calfw

(use-package calfw                                                              ; Calendar view for org agenda
  :config
  (setq
   cfw:fchar-junction ?╋                                                        ; Unicode characters
   cfw:fchar-vertical-line ?┃
   cfw:fchar-horizontal-line ?━
   cfw:fchar-left-junction ?┣
   cfw:fchar-right-junction ?┫
   cfw:fchar-top-junction ?┯
   cfw:fchar-top-left-corner ?┏
   cfw:fchar-top-right-corner ?┓

   cfw:render-line-breaker 'cfw:render-line-breaker-wordwrap                    ; Word wrap

   cfw:org-capture-template '("z"))                                           ; Capture template

  (add-to-list 'org-capture-templates
               '("z" ""
                 entry (file "/ssh:android@home:Org/calendar.org")
                 "* %^{Meeting}\n SCHEDULED: %(cfw:org-capture-day)\n%?"
                 :empty-lines 1
                 :prepend t))

  (add-to-list 'display-buffer-alist '("*cfw-calendar*"
                                       (display-buffer-reuse-window display-buffer-in-side-window)
                                       (side . top)
                                       (slot . 1)
                                       (window-width . 0.4)
                                       (reusable-frames . nil)))

  :general
  (:keymaps 'cfw:calendar-mode-map
   :states  'normal
   "s"      'cfw:navi-next-week-command
   "d"      'cfw:navi-previous-week-command
   "t"      'cfw:navi-previous-day-command
   "r"      'cfw:navi-next-day-command
   "RET"    'cfw:org-onclick
   "SPC"    'cfw:org-open-agenda-day
   "þ"      'cfw:navi-previous-month-command
   "®"      'cfw:navi-next-month-command
   "ð"      'cfw:navi-prev-item-command
   "ß"      'cfw:navi-next-item-command
   "M"      'cfw:change-view-month
   "W"      'cfw:change-view-week
   "D"      'cfw:change-view-day
   "c"      'cfw:org-capture
   "u"      'cfw:refresh-calendar-buffer))

(use-package calfw-org)

;;;;; Org-tree-slide

(use-package org-tree-slide
  :general
  (:keymaps 'org-tree-slide-mode-map
   :states  'normal
   "ð"      'org-tree-slide-move-previous-tree
   "ß"      'org-tree-slide-move-next-tree))

;;;; Project management
;;;;; Projectile

(use-package projectile
  :config
  (projectile-clear-known-projects)
  (setq projectile-completion-system 'ivy
        projectile-track-known-projects-automatically nil
        projectile-auto-discover nil
        projectile-ignored-project-function 'file-remote-p
        projectile-project-types nil
        projectile-project-root-files nil
        projectile-project-root-files-top-down-recurring nil
        projectile-project-root-files-bottom-up '(".git")))

;;;;; Counsel-projectile

(use-package counsel-projectile)

;;;;; Perspectives

(use-package persp-mode
  :demand
  :after doom-modeline

  :init
  (persp-mode)

  :config
  (setq persp-kill-foreign-buffer-behaviour 'kill                               ;Allow killing buffers that are not in the persp
        persp-set-last-persp-for-new-frames nil                                 ;Do not restore the current persp in a new frame
        persp-init-new-frame-behaviour-override nil                             ;and let us set initial-buffer-choice
        persp-auto-save-persps-to-their-file nil                                ;and not save perspectives!
        persp-auto-save-opt 0
        persp-auto-save-num-of-backups nil
        persp-save-dir nil
        persp-autokill-persp-when-removed-last-buffer 'kill-auto)

  ;; Customize appearance of the perspective widget
  (defface persp-selected-face                                                  ; Face for current persp
    '((t (:weight bold :foreground "Blue")))
    "The face used to highlight the current perspective on the modeline.")

  (defun persp-intersperse (list interspersed-val)                              ; Helper function to intersperse a separator
    "Intersperse a value into a list.
Return a new list made from taking LIST and inserting
INTERSPERSED-VAL between every pair of items.

For example, (persp-intersperse '(1 2 3) 'a) gives '(1 a 2 a 3)."
    (reverse
     (cl-reduce
      (lambda (list el) (if list (cl-list* el interspersed-val list) (list el)))
      list :initial-value nil)))

  (defun persp-format-name (name)                                               ; Apply persp-selected-face if current persp
    "Format the perspective name given by NAME for display in the mode line or header line."
    (let ((string-name (format "%s" name)))
      (if (equal name (safe-persp-name (get-current-persp)))
        (propertize string-name 'face 'persp-selected-face)
        (propertize string-name 'face 'persp-face-lighter-nil-persp))))

  (defun doom-modeline-update-persp-name (&rest _)                              ; Override doom modeline function with the one from perspective.el
    "Update perspective name in mode-line."
    (setq doom-modeline--persp-name
          (append '("[")
                  (persp-intersperse (mapcar 'persp-format-name (persp-names-sorted)) "|")
                  '("]")))))

;;;;; Projectorg

(quelpa '(projectorg :fetcher git :url "me:projectorg"))

(use-package projectorg
  :load-path "~/.config/emacs/quelpa/build/projectorg"

  :demand

  :config
  (setq projectorg/projects-root "/home/maxx/Projects/"
        projectorg/org-dir "org/"
        projectorg/projects-file (concat projectorg/projects-root projectorg/org-dir "projects.org")
        initial-buffer-choice projectorg/projects-file)

  (setq projectorg/counsel-org-capture-templates                                ; Per-project capture templates
        `(("tp"
           "[${name}] Todo"
           entry (file+headline ,(concat projectorg/projects-root projectorg/org-dir "${name}.org") "Tasks")
           "* TODO %^{todo}\n\n%a\n\n%?"
           :empty-lines 1
           :prepend t)
          ("np"
           "[${name}] Note"
           entry (file+headline ,(concat projectorg/projects-root projectorg/org-dir "${name}.org") "Notes")
           "* %^{title}\n\n%?"
           :empty-lines 1
           :prepend t)))

  :general
  (spcleader
    "p"     '(:ignore t :which-key "Projectile")
    "pf"    'counsel-projectile-find-file
    "po"    'projectorg/go-to-notes
    "pO"    'projectorg/go-to-inbox
    "pc"    '((lambda () (interactive)
                (find-file-other-window "/ssh:android@home:Org/calendar.org"))
              :which-key "Go to calendar file")
    "pb"    'persp-switch-to-buffer
    "pp"    'persp-switch
    "pg"    'counsel-projectile-grep
    "pr"    'projectile-replace-regexp
    "pk"    'projectorg/remove-from-project-list
    "p SPC" '((lambda () (interactive)
                (persp-switch "none")
                (delete-other-windows)
                (find-file projectorg/projects-file))
              :which-key "Go to projects")))

;;;; Jump to definition

;; Define another version of xref-find-definitions for indirect buffer.
(defun xref-find-definitions-indirect-buffer (identifier)
    "Like `xref-find-definitions' but switch to an indirect buffer in a new window."
  (interactive (list (xref--read-identifier "Find definitions of: ")))
  (xref--find-definitions identifier 'indirect))

;; Re-implement xref--pop-to-location with 'indirect option.
(defun xref--pop-to-location (item &optional action)
  "Go to the location of ITEM and display the buffer.
ACTION controls how the buffer is displayed:
  nil        -- switch-to-buffer
  `window'   -- pop-to-buffer (other window)
  `frame'    -- pop-to-buffer (other frame)
  `indirect' -- pop-to-indirect-buffer (other window)
If SELECT is non-nil, select the target window."
  (let* ((marker (save-excursion
                   (xref-location-marker (xref-item-location item))))
         (buf (marker-buffer marker)))
    (cl-ecase action
      ((nil)  (progn (switch-to-buffer buf) (xref--goto-char marker)))
      (window (progn (pop-to-buffer buf t) (xref--goto-char marker)))
      (frame  (let ((pop-up-frames t))
                (pop-to-buffer buf t)
                (xref--goto-char marker)))
      (indirect (let* ((newname (generate-new-buffer-name "fundef"))
                       (buf (make-indirect-buffer buf newname)))
                  (pop-to-buffer buf t)
                  (xref--goto-char marker)
                  (narrow-to-defun)))))
  (let ((xref--current-item item))
    (run-hooks 'xref-after-jump-hook)))

(use-package dumb-jump
  :config
  (setq dumb-jump-selector 'ivy)
  (add-to-list 'dumb-jump-language-file-exts '(:language "elisp" :ext "org" :agtype "elisp" :rgtype "elisp"))

  :general
  (spcleader
    "d" 'xref-find-definitions-other-window)

  :hook (ess-r-mode . (lambda () (add-to-list 'xref-backend-functions 'dumb-jump-xref-activate)))
        (poly-markdown+r-mode . (lambda () (add-to-list 'xref-backend-functions 'dumb-jump-xref-activate)))
        (poly-org-mode . (lambda () (add-to-list 'xref-backend-functions 'dumb-jump-xref-activate)))
        (slime-mode . (lambda () (add-to-list 'xref-backend-functions 'dumb-jump-xref-activate))))

;;;; CSV mode

(use-package csv-mode)

;;;; Lua
;;;;; Lua-mode

(use-package lua-mode)

;;;;; Company-lua

(use-package company-lua)

;;;;; fennel-mode

(use-package fennel-mode

  :config
  (add-to-list 'auto-mode-alist '("\\.fnl\\'" . fennel-mode)))

;;;; ESS
;;;;; ESS

(use-package ess
  :config
  (setq ess-ask-for-ess-directory nil
        comint-scroll-to-bottom-on-input t
        comint-scroll-to-bottom-on-output t
        ess-use-ido nil
        ess-style 'RStudio
        ess-eldoc-show-on-symbol t)

  (add-to-list 'evil-insert-state-modes 'comint-mode)

  (add-to-list 'display-buffer-alist '("*R Dired"
                                       (display-buffer-reuse-window display-buffer-in-side-window)
                                       (side . right)
                                       (slot . 1)
                                       (window-width . 0.2)
                                       (reusable-frames . nil)))
  (add-to-list 'display-buffer-alist '("\\*Help\\[R"
                                       (display-buffer-reuse-window display-buffer-in-side-window)
                                       (side . right)
                                       (window-width . 0.4)
                                       (reusable-frames . nil)))
  (add-to-list 'display-buffer-alist '("*R"
                                       (display-buffer-reuse-window display-buffer-in-side-window)
                                       (window-height . 0.3)
                                       (reusable-frames . nil)))

  :general
  (spcleader
    "r"   '(:ignore t :which-key "R")
    "rh"  'ess-display-help-on-object
    "rH"  'ess-handy-commands
    "rc"  'polymode-eval-region-or-chunk
    "ra"  'polymode-eval-buffer-from-beg-to-point
    "rs"  'ess-switch-process
    "rq"  'ess-quit
    "rd"  '(:ignore t :which-key "roxygen Documentation")
    "rdd" 'ess-roxy-update-entry
    "rdh" 'ess-roxy-preview-HTML
    "rdt" 'ess-roxy-preview-text)

  (:keymaps 'ess-r-mode-map
   :states  'normal
   "RET"    'ess-eval-line-and-step)

  (:keymaps 'ess-r-mode-map
   :states  'visual
   "RET"    'ess-eval-region)

  (:keymaps 'ess-r-mode-map
   :states  'insert
   "»"      '(lambda () (interactive) (insert "%>%"))
   " "      '(lambda () (interactive) (insert " ")))

  (:keymaps 'ess-r-help-mode-map
   :states  'normal
   "q" 'kill-buffer-and-window
   "TAB" 'forward-button
   "ð" 'ess-skip-to-previous-section
   "ß" 'ess-skip-to-next-section)

  (:keymaps 'inferior-ess-r-mode-map
   :states  'insert
   "TAB"    'company-complete
   "C-l"    'comint-clear-buffer
   "þ"      'comint-kill-input
   "ð"      'comint-previous-matching-input-from-input
   "ß"      'comint-next-matching-input-from-input
   "»"      '(lambda () (interactive) (insert "%>%"))
   " "      '(lambda () (interactive) (insert " ")))

  (:keymaps 'inferior-ess-r-mode-map
   :states  '(insert normal)
   "C-d"    'evil-scroll-line-up
   "C-s"    'evil-scroll-line-down)

  (:keymaps 'inferior-ess-r-mode-map
   :states  'normal
   "ð"      'comint-previous-prompt
   "ß"      'comint-next-prompt)

  :hook
  (comint-mode . (lambda () (setq-local scroll-margin 0)))                      ; Display console output without margin
  (ess-r-help-mode . (lambda ()
                     (setq buffer-face-mode-face '(:background "#102030"))
                     (buffer-face-mode 1))))

;;;;; Poly-R

(use-package poly-R
  :general
  (spcleader
     "r"  '(:ignore t :which-key "R")
     "rc" 'polymode-eval-region-or-chunk
     "ra" 'polymode-eval-buffer-from-beg-to-point
     "re" 'polymode-export
     "rE" 'polymode-set-exporter)

  (:keymaps '(markdown-mode-map)
   :states  'normal
   "<tab>"  'markdown-cycle
   "ð"      'markdown-previous-visible-heading
   "ß"      'markdown-next-visible-heading
   "Ð"      'markdown-outline-previous-same-level
   "ẞ"      'markdown-outline-next-same-level
   "þ"      'outline-hide-subtree
   "®"      '(lambda () (interactive)
              (outline-show-children)
              (outline-show-entry))
   "Þ"      'markdown-up-heading
   "©"      'polymode-next-chunk
   "ſ"      'polymode-previous-chunk
   "M-r"    'markdown-demote
   "M-t"    'markdown-promote
   "M-d"    'markdown-move-up
   "M-s"    'markdown-move-down))

;;;; Git
;;;;; Magit

(use-package magit
  :config
  (setq magit-status-goto-file-position t
        magit-popup-show-help-echo nil
        magit-clone-default-directory projectorg/projects-root
        magit-clone-set-remote.pushDefault t)

  (add-to-list 'evil-emacs-state-modes 'magit-mode)
  (add-to-list 'evil-emacs-state-modes 'git-rebase-mode)

  (add-to-list 'display-buffer-alist '("magit"
                                       (display-buffer-reuse-window display-buffer-in-side-window)
                                       (side . left)
                                       (window-width . 80)
                                       (reusable-frames . nil)))
  (add-to-list 'display-buffer-alist '("magit-revision"
                                       (display-buffer-reuse-window display-buffer-in-side-window)
                                       (side . left)
                                       (slot . 1)
                                       (window-height . .5)
                                       (window-width . 80)
                                       (reusable-frames . nil)))
  (add-to-list 'display-buffer-alist '("magit-diff"
                                       (display-buffer-reuse-window display-buffer-in-side-window)
                                       (side . left)
                                       (slot . 1)
                                       (window-height . .5)
                                       (window-width . 80)
                                       (reusable-frames . nil)))

  :general
  (spcleader
    "g"  '(:ignore t :which-key "Magit")
    "gd" 'magit-dispatch
    "gf" 'magit-file-dispatch
    "gs" 'magit-status)

  (:keymaps '(magit-hunk-section-map
              magit-file-section-map
              magit-mode-map
              magit-staged-section-map
              magit-unstaged-section-map
              magit-revision-mode-map
              magit-section-map
              magit-refs-mode-map
              magit-log-mode-map
              magit-diff-mode-map
              magit-untracked-section-map
              magit-status-mode-map
              magit-stash-section-map)
   "ð"      'magit-section-backward
   "ß"      'magit-section-forward
   "þ"      'magit-section-hide
   "®"      'magit-section-show
   "s"      'magit-next-line
   "d"      'magit-previous-line
   "q"      'kill-buffer-and-window)

  (:keymaps '(magit-hunk-section-map
              magit-status-mode-map
              magit-unstaged-section-map
              magit-untracked-section-map)
   "+"      'magit-stage
   "-"      'magit-unstage))

;;;;; Magit-annex

(use-package magit-annex)

;;;;; Magit-todos

(use-package magit-todos
  :init
  (magit-todos-mode))

;;;;; Smerge

(use-package smerge-mode
  :general
  (:keymaps 'smerge-mode-map
   :states  'normal
   "RET"    'smerge-keep-current
   "n"      'smerge-next
   "p"      'smerge-prev))

;;;;; Git-gutter-fringe

(use-package git-gutter-fringe
  :init
  (global-git-gutter-mode t))

;;;; Elpy

(use-package elpy
  :init
  ;; (elpy-enable)
  )

;;;; Slime
(use-package slime-company
  :after (slime company)

  :config
  (slime-setup '(slime-fancy slime-company))
  (setq slime-company-completion 'fuzzy
        slime-company-after-completion 'slime-company-just-one-space)

  :general
  (:keymaps 'company-active-map
   "ß"       'company-select-next
   "ð"       'company-select-previous
   "†"       'company-show-doc-buffer
   "¿"       'company-show-location))

(use-package slime
  :config
  (setq inferior-lisp-program "sbcl")

  (add-to-list 'evil-emacs-state-modes 'sldb-mode)

  :general
  (:keymaps 'slime-parent-map
   :states  'normal
   "RET"    'slime-eval-defun)

  (:keymaps 'sldb-mode-map
   "ð"      'sldb-up
   "d"      'sldb-up
   "Ð"      'sldb-details-up
   "ß"      'sldb-down
   "s"      'sldb-down
   "ẞ"      'sldb-details-down
   " "      'sldb-step
   "®"      'sldb-toggle-details
   "þ"      'sldb-toggle-details
   "RET"    'sldb-show-source)

  (:keymaps 'slime-repl-mode-map
   :states  'insert
   "TAB"    'company-complete
   "ð"      'slime-repl-previous-input
   "ß"      'slime-repl-next-input
   "þ"      'slime-repl-kill-input
   "C-l"    'slime-repl-clear-buffer)

  (:keymaps 'slime-repl-mode-map
   :states  'normal
   "ð"      'slime-repl-previous-prompt
   "ß"      'slime-repl-next-prompt)

  (:keymaps 'slime-repl-mode-map
   :states  '(insert normal)
   "C-d"    'evil-scroll-line-up
   "C-s"    'evil-scroll-line-down))

;;;; Flycheck

(use-package flycheck
  :init
  (global-flycheck-mode))

;;;; Mu4e
;;;;; Mu4e

(use-package mu4e
  :demand

  :load-path "/usr/share/emacs/site-lisp/mu4e/"

  :config
  (add-to-list 'evil-emacs-state-modes 'mu4e-main-mode)

  (setq mu4e-sent-folder "/Inbox"                                               ; Folders
        mu4e-drafts-folder "/Drafts"
        mu4e-trash-folder "/Trash"
        mu4e-refile-folder "/Archives")

  (setq mu4e-maildir-shortcuts                                                  ; and their shortcuts
        '(("/Inbox"    . ?i)
          ("/Archives" . ?a)
          ("/Trash"    . ?t)
          ("/Junk"     . ?j)
          ("/Sent"     . ?s)
          ("/Drafts"   . ?d)))


  (setq mu4e-view-prefer-html t                                                 ; Display html by default
        mu4e-get-mail-command "mbsync free"
        mu4e-update-interval 300                                                ; Fetch emails every 5 minutes
        mu4e-headers-auto-update t                                              ; Auto update list of emails after update
        mu4e-compose-signature-auto-include nil                                 ; org-msg has its own signature
        mu4e-compose-format-flowed t
        mu4e-attachment-dir "~/Downloads"
        mu4e-compose-in-new-frame nil
        mu4e-view-show-images t
        mu4e-headers-sort-direction 'ascending
        mu4e-confirm-quit nil
        mu4e-change-filenames-when-moving t                                     ; Required by mbsync
        message-kill-buffer-on-exit t                                           ; Discard editing buffer when message is sent
        mu4e-compose-dont-reply-to-self t
        mu4e-completing-read-function 'ivy-completing-read
        mu4e-split-view 'vertical
        mu4e-headers-visible-columns 95 
        mu4e-headers-include-related nil                                        ; Hide related messages by default
        mu4e-headers-skip-duplicates t                                          ; and skip duplicates
        mu4e-headers-results-limit 500
        mu4e-index-cleanup t                                                    ; Keep mu index clean
        mu4e-index-lazy-check nil
        mail-user-agent 'mu4e-user-agent
        mu4e-compose-reply-recipients 'all                                      ; Reply to all by default
        mu4e-view-show-addresses t                                              ; Always show email addresses
        mu4e-use-fancy-chars t                                                  ; Use fancy chars
        mu4e-headers-thread-first-child-prefix '("o " . "├ ")
        mu4e-headers-thread-last-child-prefix '("L " . "└ ")
        mu4e-headers-attach-mark '("a" . "")
        mu4e-headers-visible-flags '(attach encrypted signed))

  (setq mm-text-html-renderer 'gnus-w3m)

  (setq mu4e-headers-fields                                                     ; Define headers
        '((:thread-subject . 50)
          (:from-or-to . 20)
          (:human-date . 11)
          (:flags . 4)))

  (when (fboundp 'imagemagick-register-types)                                   ; Use imagemagick to view images, if available
    (imagemagick-register-types))

  :general
  (:keymaps 'mu4e-main-mode-map
   "'"      'mu4e~headers-jump-to-maildir)

  (:keymaps 'mu4e-headers-mode-map
   :states  'normal
   "ð"      'mu4e-headers-prev
   "ß"      'mu4e-headers-next
   "RET"    'mu4e-headers-view-message
   "®"      'mu4e-headers-view-message
   "q"      'mu4e~headers-quit-buffer
   "x"      'mu4e-headers-mark-for-trash
   "a"      'mu4e-headers-mark-for-refile
   "u"      'mu4e-headers-mark-for-unmark
   "l"      'mu4e-headers-mark-for-trash
   "U"      'mu4e-mark-unmark-all
   "X"      'mu4e-mark-execute-all
   "W"      'mu4e-headers-toggle-include-related
   "C"      'mu4e-compose-new
   "F"      'mu4e-compose-forward
   "R"      'mu4e-compose-reply
   "m"      'mu4e-update-mail-and-index
   "o"      'mu4e-headers-change-sorting
   "'"      'mu4e~headers-jump-to-maildir
   "M"      'mu4e-headers-mark-for-move
   "/"      'mu4e-view-search-narrow)

  (:keymaps 'mu4e-headers-mode-map
   :states  'visual
   "l"      'mu4e-headers-mark-for-delete)

  (:keymaps 'mu4e-view-mode-map
   :states  'normal
   "ð"      'mu4e-view-headers-prev
   "ß"      'mu4e-view-headers-next
   "þ"      'mu4e-select-other-view
   "q"      'kill-buffer-and-window
   "x"      'mu4e-view-mark-for-trash
   "a"      'mu4e-view-mark-for-refile
   "u"      'mu4e-view-mark-for-unmark
   "l"      'mu4e-view-mark-for-trash
   "U"      'mu4e-mark-unmark-all
   "X"      'mu4e-mark-execute-all
   "C"      'mu4e-compose-new
   "F"      'mu4e-compose-forward
   "R"      'mu4e-compose-reply
   "m"      'mu4e-update-mail-and-index
   "'"      'mu4e~headers-jump-to-maildir
   "h"      'mu4e-view-toggle-html
   "M"      'mu4e-view-mark-for-move
   "A"      'mu4e-view-action
   "J"      'mu4e-view-save-attachments))

;;;;; Mu4e-alert

(defun maxx/mu4e-alert-notification-formatter (mail-group all-emails)
  "Define a custom mu4e-alert formatter for MAIL-GROUP notification.
ALL-EMAILS are all the unread emails"
  (list :title (format "%s  \uf0e0" (mu4e-alert--get-group (car mail-group)))
        :body ""))

(use-package mu4e-alert
  :after alert

  :config
  (mu4e-alert-set-default-style 'libnotify)
  (setq mu4e-alert-email-notification-types '(subjects))
  (setq mu4e-alert-grouped-mail-notification-formatter 'maxx/mu4e-alert-notification-formatter)

  (mu4e-alert-enable-notifications))

;;;;; smtpmail

(use-package smtpmail
  :config
  (setq smtpmail-queue-mail nil
        message-send-mail-function 'smtpmail-send-it
        send-mail-function 'smtpmail-send-it)

  (setq smtpmail-smtp-server "smtp.free.fr"
        user-mail-address "maximewack@free.fr"
        auth-sources '("~/.authinfo.gpg")
        smtpmail-smtp-service 587)

  (setq mu4e-main-hide-personal-addresses t
        mu4e-context-policy 'pick-first
        mu4e-compose-context-policy 'ask-if-none)

  (setq mu4e-contexts
        `( ,(make-mu4e-context
             :name "free"
             :enter-func (lambda () (mu4e-message "Entering free context"))
             :leave-func (lambda () (mu4e-message "Leaving free context"))
             ;; we match based on the contact-fields of the message
             :match-func (lambda (msg)
                           (when msg
                             (mu4e-message-contact-field-matches msg :to "maximewack@free.fr")))
             :vars '((user-mail-address      . "maximewack@free.fr")
                     (smtpmail-smtp-server	 . "smtp.free.fr")
                     (user-full-name         . "Maxime Wack")
                     (org-msg-signature      . "--\nMaxime Wack\n")))
           ,(make-mu4e-context
             :name "maximewack.com"
             :enter-func (lambda () (mu4e-message "Switch to the home context"))
             :leave-func (lambda () (mu4e-message "Leaving home context"))
             :match-func (lambda (msg)
                           (when msg
                             (mu4e-message-contact-field-matches msg :to "@maximewack.com")))
             :vars '((user-mail-address      . "@maximewack.com")
                     (smtpmail-smtp-server	 . "drykiss.me")
                     (user-full-name         . "Maxime Wack")
                     (org-msg-signature      . "--\nMaxime Wack\n")))

            ,(make-mu4e-context
               :name "drykiss.me"
               :enter-func (lambda () (mu4e-message "Switch to the drykiss context"))
               :leave-func (lambda () (mu4e-message "Leaving drykiss context"))
               :match-func (lambda (msg)
                             (when msg
                               (mu4e-message-contact-field-matches msg :to "@drykiss.me")))
               :vars '((user-mail-address      . "@drykiss.me")
                       (smtpmail-smtp-server	 . "drykiss.me")
                       (user-full-name         . "" )
                       (org-msg-signature      . nil))))))

;;;;; Org-mime

(use-package org-mime)

;;;;; Org-msg

(use-package org-msg
  :init
  (org-msg-mode)

  :config                                                                       ; Customize signature depending on host name
  (if (equal (system-name) "hegp")                                              ; If at work, use formal signature, else just sign "Maxime"
      (setq org-msg-signature "

--

Dr Maxime Wack, MSc
Assistant Hospitalo-Universitaire
Pôle Informatique et Santé Publique
Hôpital Européen Georges Pompidou
tel: 01 56 09 23 63")
    (setq org-msg-signature "

--

Maxime Wack"))

  (setq maxx/org-msg-style                                                      ; Message style without max-width = 100ch
        '((del nil ((font-family . "\"Arial\"")                                 ; This fixes narrow columns in message preview
                    (font-size . "10pt")                                        ; in outlook webapp
                    (color . "grey")
                    (border-left . "none")
                    (text-decoration . "line-through")
                    (margin-bottom . "0px")
                    (margin-top . "10px")
                    (line-height . "11pt")))
          (a nil ((color . "#0071c5")))
          (a reply-header ((color . "black")
                           (text-decoration . "none")))
          (div reply-header ((padding . "3.0pt 0in 0in 0in")
                             (border-top . "solid #e1e1e1 1.0pt")
                             (margin-bottom . "20px")))
          (span underline ((text-decoration . "underline")))
          (li nil ((font-family . "\"Arial\"")
                   (font-size . "10pt")
                   (line-height . "10pt")
                   (margin-bottom . "0px")
                   (margin-top . "2px")))
          (nil org-ul ((list-style-type . "square")))
          (nil org-ol ((font-family . "\"Arial\"")
                       (font-size . "10pt")
                       (line-height . "10pt")
                       (margin-bottom . "0px")
                       (margin-top . "0px")
                       (margin-left . "30px")
                       (padding-top . "0px")
                       (padding-left . "5px")))
          (nil signature ((font-family . "\"Arial\"")
                          (font-size . "10pt")
                          (margin-bottom . "20px")))
          (blockquote nil ((padding-left . "5px")
                           (margin-left . "10px")
                           (margin-top . "20px")
                           (margin-bottom . "0")
                           (border-left . "3px solid #ccc")
                           (font-style . "italic")
                           (background . "#f9f9f9")))
          (code nil ((font-size . "10pt")
                     (font-family . "monospace")
                     (background . "#f9f9f9")))
          (code src\ src-asl ((color . "unspecified-fg")
                              (background-color . "unspecified-bg")))
          (code src\ src-c ((color . "unspecified-fg")
                            (background-color . "unspecified-bg")))
          (code src\ src-c++ ((color . "unspecified-fg")
                             (background-color . "unspecified-bg")))
          (code src\ src-conf ((color . "unspecified-fg")
                               (background-color . "unspecified-bg")))
          (code src\ src-cpp ((color . "unspecified-fg")
                              (background-color . "unspecified-bg")))
          (code src\ src-csv ((color . "unspecified-fg")
                              (background-color . "unspecified-bg")))
          (code src\ src-diff ((color . "unspecified-fg")
                               (background-color . "unspecified-bg")))
          (code src\ src-ditaa ((color . "unspecified-fg")
                                (background-color . "unspecified-bg")))
          (code src\ src-emacs-lisp ((color . "unspecified-fg")
                                     (background-color . "unspecified-bg")))
          (code src\ src-fundamental ((color . "unspecified-fg")
                                      (background-color . "unspecified-bg")))
          (code src\ src-ini ((color . "unspecified-fg")
                              (background-color . "unspecified-bg")))
          (code src\ src-json ((color . "unspecified-fg")
                               (background-color . "unspecified-bg")))
          (code src\ src-makefile ((color . "unspecified-fg")
                                   (background-color . "unspecified-bg")))
          (code src\ src-man ((color . "unspecified-fg")
                              (background-color . "unspecified-bg")))
          (code src\ src-org ((color . "unspecified-fg")
                              (background-color . "unspecified-bg")))
          (code src\ src-plantuml ((color . "unspecified-fg")
                                   (background-color . "unspecified-bg")))
          (code src\ src-python ((color . "unspecified-fg")
                                 (background-color . "unspecified-bg")))
          (code src\ src-sh ((color . "unspecified-fg")
                             (background-color . "unspecified-bg")))
          (code src\ src-xml ((color . "unspecified-fg")
                              (background-color . "unspecified-bg")))
          (nil linenr ((padding-right . "1em")
                       (color . "black")
                       (background-color . "#aaaaaa")))
          (pre nil ((line-height . "12pt")
                    (color . "unspecified-fg")
                    (background-color . "unspecified-bg")
                    (margin . "0px")
                    (font-size . "9pt")
                    (font-family . "monospace")))
          (div org-src-container ((margin-top . "10px")))
          (nil figure-number ((font-family . "\"Arial\"")
                              (font-size . "10pt")
                              (color . "#0071c5")
                              (font-weight . "bold")
                              (text-align . "left")))
          (nil table-number)
          (caption nil ((text-align . "left")
                        (background . "#0071c5")
                        (color . "white")
                        (font-weight . "bold")))
          (nil t-above ((caption-side . "top")))
          (nil t-bottom ((caption-side . "bottom")))
          (nil listing-number ((font-family . "\"Arial\"")
                               (font-size . "10pt")
                               (color . "#0071c5")
                               (font-weight . "bold")
                               (text-align . "left")))
          (nil figure ((font-family . "\"Arial\"")
                       (font-size . "10pt")
                       (color . "#0071c5")
                       (font-weight . "bold")
                       (text-align . "left")))
          (nil org-src-name ((font-family . "\"Arial\"")
                             (font-size . "10pt")
                             (color . "#0071c5")
                             (font-weight . "bold")
                             (text-align . "left")))
          (table nil ((font-family . "\"Arial\"")
                      (font-size . "10pt")
                      (margin-top . "0px")
                      (line-height . "10pt")
                      (border-collapse . "collapse")))
          (th nil ((border . "1px solid white")
                   (background-color . "#0071c5")
                   (color . "white")
                   (padding-left . "10px")
                   (padding-right . "10px")))
          (td nil ((font-family . "\"Arial\"")
                   (font-size . "10pt")
                   (margin-top . "0px")
                   (padding-left . "10px")
                   (padding-right . "10px")
                   (background-color . "#f9f9f9")
                   (border . "1px solid white")))
          (td org-left ((text-align . "left")))
          (td org-right ((text-align . "right")))
          (td org-center ((text-align . "center")))
          (div outline-text-4 ((margin-left . "15px")))
          (div outline-4 ((margin-left . "10px")))
          (h4 nil ((margin-bottom . "0px")
                   (font-size . "11pt")
                   (font-family . "\"Arial\"")))
          (h3 nil ((margin-bottom . "0px")
                   (text-decoration . "underline")
                   (color . "#0071c5")
                   (font-size . "12pt")
                   (font-family . "\"Arial\"")))
          (h2 nil ((margin-top . "20px")
                   (margin-bottom . "20px")
                   (font-style . "italic")
                   (color . "#0071c5")
                   (font-size . "13pt")
                   (font-family . "\"Arial\"")))
          (h1 nil ((margin-top . "20px")
                   (margin-bottom . "0px")
                   (color . "#0071c5")
                   (font-size . "12pt")
                   (font-family . "\"Arial\"")))
          (p nil ((text-decoration . "none")
                  (margin-bottom . "0px")
                  (margin-top . "10px")
                  (line-height . "11pt")
                  (font-size . "10pt")
                  (font-family . "\"Arial\"")
                  ;; (max-width . "100ch")
                  ))
          (div nil ((font-family . "\"Arial\"")
                    (font-size . "10pt")
                    (line-height . "11pt")))))

  (setq org-msg-enforce-css maxx/org-msg-style
        org-msg-default-alternatives '((new html)
                                       (reply-to-html html)
                                       (reply-to-text html))))

;;;;; Htmlize

(use-package htmlize)

;;;; seriesTracker

(use-package seriestracker
  ;; :load-path "/home/maxx/Projects/seriestracker"
  :config
  (setq seriestracker--fold-cycle 'seriestracker-all-unfolded)

  (defun seriestracker-search-tpb ()
    "Search on tpb."
    (interactive)
    (seriestracker--inbuffer)
    (seriestracker--with-episode
     ((seriesname (alist-get 'name series)))
     ;; (browse-url-xdg-open (concat "https://piratebayproxy.live/search/" seriesname " S" (format "%02d" seasonN) "E" (format "%02d" episodeN)))
     (browse-url-xdg-open (concat "https://thepiratebay.org/search.php?q=" seriesname " S" (format "%02d" seasonN) "E" (format "%02d" episodeN)))
     ))

  :general
  (:keymaps 'seriestracker-mode-map
   :states  '(normal visual)
   "d"      'seriestracker-prev-line
   "s"      'seriestracker-next-line
   "ð"      'seriestracker-prev
   "ß"      'seriestracker-next
   "Þ"      'seriestracker-up
   "Ð"      'seriestracker-prev-same
   "ẞ"      'seriestracker-next-same
   "þ"      'seriestracker-fold-at-point
   "®"      'seriestracker-unfold-at-point
   "h"      'seriestracker-dispatch
   "U"      'seriestracker-update
   "A"      'seriestracker-search
   "w"      'seriestracker-toggle-watch
   "u"      'seriestracker-watch-up
   "W"      'seriestracker-toggle-display-watched
   "N"      'seriestracker-add-note
   "q"      'seriestracker-quit
   [tab]    'seriestracker-cycle
   "RET"    'seriestracker-search-tpb))

;;;; Academic writing

;;;;; plantuml

(use-package plantuml-mode
  :config

  (setq plantuml-jar-path "/usr/share/java/plantuml/plantuml.jar"
        plantuml-default-exec-mode 'jar
        org-plantuml-jar-path plantuml-jar-path))

;;;;; academic-phrases

(use-package academic-phrases)

;;;; Font Awesome

(use-package fontawesome)

;;;; OSM

(use-package osm
  :config
  (setq osm-home '(48.8443 2.3199 17))
  (add-to-list 'osm-server-list
               '(maptiler-satellite-hybrid
                 :name "MapTiler Satellite Hybrid"
                 :description "(Non-free API)"
                 :max-connections 8
                 :url "https://api.maptiler.com/maps/hybrid/256/%z/%x/%y.jpg?key=IdeGh4b0rGWjL4i4X9Jq"))

  :general
  (:keymaps 'osm-mode-map
   :states  'normal
   "D"      'osm-up-up
   "S"      'osm-down-down
   "T"      'osm-left-left
   "R"      'osm-right-right
   "d"      'osm-up
   "s"      'osm-down
   "t"      'osm-left
   "r"      'osm-right
   "-"      'osm-zoom-out
   "+"      'osm-zoom-in
   "l"      'osm-zoom-out
   "v"      'osm-zoom-in
   "?"      'osm-search
   "/"      'osm-search))


;;;; Elfeed

(use-package elfeed
  :config
  (setq elfeed-feeds '("https://news.ycombinator.com/rss")
        elfeed-search-title-max-width 200
        elfeed-search-title-min-width 200)

  :general
  (:keymaps 'elfeed-search-mode-map
            :states 'normal
            "U" 'elfeed-update
            "u" 'elfeed-search-tag-all-unread
            "ð" 'evil-previous-line
            "ß" 'evil-next-line
            "®" 'elfeed-search-browse-url
            "þ" 'elfeed-search-untag-all-unread
            "q" 'elfeed-search-quit-window))
