;;; package --- Summary
;;; Commentary:
;;; Code:
;;; Use-package

;; Use package and melpa as source
(require 'package)
(add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/"))
(add-to-list 'package-archives '("gnu" . "http://elpa.gnu.org/packages/"))
(setq package-enable-at-startup nil)
(package-initialize)

;; use-package
(setq-default
 use-package-always-ensure t
 use-package-expand-minimally t
 use-package-verbose nil
 use-package-enable-imenu-support t)

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

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

(setq custom-file "~/Projects/dotfiles/.emacs.d/custom.el")
(load custom-file)

;;;; Options

;;;;; Mode-line

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

;;;;; Backup

(setq
 ;; delete excess backup versions silently
 delete-old-versions t
 ;; make backup files
 make-backup-files t
 ;; Use version control on backups
 version-control t
 ;; don't make backups file when in version controlled dir
 vc-make-backup-files nil
 ;; which directory to put backups file
 backup-directory-alist `(("." . "~/.emacs.d/backups")
                          (,tramp-file-name-regexp nil)))

;;;;; Autosave

(setq
 ;; Enable
 auto-save-default t
 ;; Set interval and timeout
 auto-save-interval 300
 auto-save-timeout 30
 ;; Set directory for auto-saves
 auto-save-file-name-transforms '((".*" "~/.emacs.d/auto-save/" t)))

;;;;; Scrolling

(setq
 scroll-margin 10
 hscroll-margin 10
 scroll-conservatively 100000
 scroll-preserve-screen-position 1
 hscroll-step 1
 maximum-scroll-margin 0.5)

;;;;; Disable GUI

(menu-bar-mode -1)
(tool-bar-mode -1)
(scroll-bar-mode -1)
(blink-cursor-mode -1)
(tooltip-mode -1)

(setq
 inhibit-startup-screen t
 inhibit-startup-message t
 inhibit-startup-echo-area-message t)

;;;;; UTF8

(setq
 coding-system-for-read    'utf-8
 coding-system-for-write   'utf-8)

;; Prefer 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 nil
      split-width-threshold 80)

;;;;; Set proxy at work

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

;;;;; Misc

;; Fix dead_circumflex with ibus

(require 'iso-transl)

;; Stop warning when using narrow
(put 'narrow-to-region 'disabled nil)

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

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

;; Add for emacs server
(add-to-list 'default-frame-alist '(font . "FiraEmacs 10"))
(add-to-list 'default-frame-alist '(alpha . (85 . 95)))

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

;; Font
(unless (equal (system-name) "hegp")
  (set-frame-font "FiraEmacs 10" nil t))

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

(defun package--save-selected-packages (&rest opt)
  "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 undmodified 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
    "RET" 'eval-defun
    "|"   'shell-command-on-region
    "."   'eval-expression
    "k"   'kill-buffer-and-window
    "$"   '((lambda () (interactive) (find-file "~/.emacs")) :which-key "open config")
    "#"   '((lambda () (interactive) (load-file "~/.emacs")) :which-key "reload config")
    "l"   'reposition-window
    "W"   '(count-words-region :which-key "word count")
    "w"   'toggle-truncate-lines)

  (spcleader
    "K"   '(:ignore t :which-key "Kill buffers")
    "Kk"  'kill-some-buffers
    "Km"  '(maxx/kill-unmodified-buffers :which-key "Kill unmodified"))

  (spcleader
    "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
    "m" '(:ignore t :which-key "Modes")
    "mo" 'org-mode
    "mm" 'mu4e
    "me" 'eshell
    "mc" 'calc
    "mC" 'calendar
    "mr" 'ess-r-mode
    "mw" 'woman))

;;;;; Hydra

(use-package hydra)

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

(use-package evil
  :demand
  :config
  (evil-mode t)
  (setq evil-want-integration nil
        evil-want-keybinding nil
        evil-want-Y-yank-to-eol t
        ;; Colored cursors based on evil-state
        evil-emacs-state-cursor    '("red" box)
        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)
        ;; use NORMAL mode/state EVERYWHERE by default
        evil-default-state 'normal
        evil-motion-state-modes nil
        evil-normal-state-modes nil
        evil-insert-state-modes nil
        ;; Use emacs state in these selected modes
        evil-emacs-state-modes nil
        ;; and don't let modes override the INSERT state (!)
        evil-overriding-maps nil
        evil-intercept-maps nil)

  (defmacro define-and-bind-text-object (key start-regex 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 "_" "_" "_")
  (define-and-bind-text-object "-" "-" "-")


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

  (defhydra hydra-window (:color red :timeout .3)
    "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" evil-window-vsplit)
    ("c" evil-window-delete)
    ("o" delete-other-windows)
    ("é" nil "Cancel"))

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

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

  (:states '(normal motion)
   "t"     'evil-backward-char
   "s"     'evil-next-visual-line
   "d"     'evil-previous-visual-line
   "r"     'evil-forward-char
   "T"     'evil-window-top
   "S"     'evil-scroll-down
   "D"     'evil-scroll-up
   "R"     'evil-window-bottom
   "l"     'evil-delete
   "L"     'evil-delete-line
   "h"     'evil-replace
   "H"     'evil-replace-state
   "gs"    'evil-next-line
   "gd"    'evil-previous-line
   "M"     'evil-window-middle
   "j"     'evil-find-char-to
   ";"     'evil-repeat-find-char-reverse
   ","     'evil-repeat-find-char
   "/"     'counsel-grep-or-swiper
   "÷"     'evil-ex
   "zt"    'evil-close-fold
   "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))))
   "zA"    'evil-toggle-fold
   "gt"    'previous-buffer
   "gr"    'next-buffer
   "gf"    'evil-find-file-at-point-with-line
   "C-s"   'evil-scroll-line-down
   "C-d"   'evil-scroll-line-up
   "C-o"   'evil-jump-backward)

  (:states 'insert
   "C-r"   'counsel-yank-pop
   "C-u"   'counsel-unicode-char
   "_"     'self-insert-command))

;;;;;; 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
  :config
  (evil-escape-mode t)
  (setq-default evil-escape-key-sequence "ii"
                evil-escape-delay 0.2))

;;;;;; Evil-commentary

(use-package evil-commentary
  :demand
  :config
  (evil-commentary-mode t)

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

;;;;;; Evil-surround

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

;;;;;; Evil-lion

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

;;;;; Which-key

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

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

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

;;;;;; Custom

(use-package cus-edit
  :ensure nil
  :config
  (add-to-list 'evil-emacs-state-modes 'Custom-mode))

;;;;;; Ediff

(use-package ediff
  :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 'evil-emacs-state-modes 'debugger-mode))

;;;;;; Paren

(use-package paren
  :config
  (show-paren-mode t)
  (setq show-paren-delay 0))

;;;;;; Flyspell

(use-package flyspell
  :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))

;;;;;; Tar-mode

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

;;;;;; Whitespace

(use-package whitespace
  :config
  (setq whitespace-style
        '(face
          tabs
          spaces
          trailing
          empty
          space-mark
          tab-mark
          ))

  :hook (before-save . whitespace-cleanup))

;;;;;; Info

(use-package info
  :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
   "s"      'evil-scroll-line-down
   "d"      'evil-scroll-line-up))

;;;;;; Highlight line

(use-package hl-line
  :config
  (global-hl-line-mode t)

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

;;;;;; Simple

(use-package simple
  :ensure nil
  :config
  (global-visual-line-mode t)

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

;;;;;; Revert

(use-package autorevert
  :config
  (global-auto-revert-mode t))

;;;;;; Elisp

(use-package elisp-mode
  :ensure nil
  :config
  ;; No size limit to output in elisp mode
  (setq eval-expression-print-length nil)

  :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)

  (: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
   "C-/"   '(lambda () (interactive) (text-scale-adjust 0))))

;;;;;; Calc

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

;;;;;; Calendar

(use-package calendar
  :config
  (calendar-set-date-style 'iso)
  (setq 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")
          ;; fetes a date variable
          (holiday-easter-etc 0   "Pâques")
          (holiday-easter-etc 1   "Lundi de Pâques")
          (holiday-easter-etc 39  "Ascension")
          (holiday-easter-etc 49  "Pentecôte")
          (holiday-easter-etc -47 "Mardi gras")
          (holiday-float 5 0 4    "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

(defun maxx/import-caldav (calendar &optional append)
  "Import caldav calendar synced on disk with vdirsyncer into the diary.
CALENDAR is the name of the calendar to import from
APPEND is whether to add new events to the diary or to reset it"
  (unless append
    (delete-file diary-file))
  (let* ((caldir (concat "~/Mail/Calendars/" calendar))
        (calfiles (directory-files-recursively caldir "\.ics$")))

  (seq-do (lambda (entry) (icalendar-import-file entry diary-file))
          calfiles)))

(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
  :demand
  :config
  (winner-mode 1)

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

;;;;;; Dired

(use-package dired
  :ensure nil
  :config
  (setq wdired-allow-to-change-permissions 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-file
   "SPC"    'dired-mark
   "X"      'dired-do-flagged-delete
   "x"      'dired-flag-file-deletion
   "W"      'wdired-change-to-wdired-mode
   "q"      'kill-buffer-and-window))

;;;;;; Tramp

(use-package tramp
  :config
  (setq tramp-terminal-type "tramp"
        tramp-default-method "sshx"))

;;;;;; Subword

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

;;;;;; Hideshow

(use-package hideshow
  :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))

;;;;; Undo-tree

(use-package undo-tree
  :demand
  :config
  (global-undo-tree-mode)
  (setq undo-tree-auto-save-history t
        undo-tree-history-directory-alist '(("." . "~/.emacs.d/undo"))
        undo-tree-enable-undo-in-region nil)

  (add-to-list 'display-buffer-alist '("*undo-tree"
                                       (display-buffer-reuse-window display-buffer-in-side-window)
                                       (side . left)
                                       (window-width . 0.15)
                                       (reusable-frames . nil)))
  :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
  :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
  :general
  (:keymaps '(Info-mode-map
              help-mode-map
              helpful-mode-map
              mu4e-view-mode-map
              org-mode-map)
   :states  'normal
   "f"      'ace-link))

;;;;; 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
  :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))

;;;;; Autopairs

(use-package autopair
  :config
  (autopair-global-mode))

;;;;; Minions

(use-package minions
  :config
  (minions-mode t)
  (setq minions-mode-line-lighter ""))

;;;;; Helpful

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

  (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
  :load-path "~/.emacs.d/Fira-code"
  :hook (prog-mode . fira-code-mode)
        (org-mode . fira-code-mode))

;;;;; Rainbow mode

(use-package rainbow-mode
  :demand
  :config
  (rainbow-mode))

;;;;; Doc view

(use-package doc-view
  :config
  (setq doc-view-continuous t
        doc-view-resolution 300)

  :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"      'image-kill-buffer
   "+"      'doc-view-enlarge
   "-"      'doc-view-shrink))

;;;;; Image Mode

(use-package image
  :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
  :general
  (:keymaps 'woman-mode-map
   :states 'normal
   "ß" 'Man-next-section
   "ð" 'Man-previous-section))

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

(use-package ivy
  :config
  ;; Start with empty regex for describe function and variable
  (setf (alist-get 'counsel-describe-function ivy-initial-inputs-alist) ""
        (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)))

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

;;;;;; Counsel

(use-package smex
  :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"   'counsel-switch-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
  :config
  (global-company-mode t)
  (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)

  :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))

;;;; Org
;;;;; Org

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

  (setq org-catch-invisible-edits 'smart
        ;; Folders
        org-directory "~/Projects/org"
        org-agenda-files (directory-files-recursively "~/Projects/org" "\.org$")
        org-default-notes-file "~/Projects/org/notes.org"
        ;; Move Attachments
        org-attach-method 'mv
        ;; Startup
        org-startup-folded 'content
        org-startup-with-inline-images t
        org-startup-indented t
        org-startup-truncated t
        org-hide-emphasis-markers t
        org-hide-block-startup t
        ;; Org sub/superscript behavior
        org-use-sub-superscripts '{}
        org-export-with-sub-superscripts '{}
        org-pretty-entities t
        org-pretty-entities-include-sub-superscripts t
        ;; RET behavior
        org-M-RET-may-split-line nil
        org-return-follows-link nil
        org-image-actual-width 100
        ;; Generate UUIDs for links when storing link
        org-id-link-to-org-use-id t
        ;; Make todos dependent
        org-html-checkbox-type 'unicode
        org-enforce-todo-checkbox-dependencies nil
        org-enforce-todo-dependencies t
        ;; Log states
        org-log-into-drawer t
        ;; Recursive todo statistics
        org-hierarchical-todo-statistics nil
        ;; Todo keywords
        org-todo-keywords '((sequence "REFILE(r)" "SOMEDAY(s)" "TODO(t)" "WAITING(w!)" "|" "DONE(d!)" "CANCELED(c@)"))
        ;; Colors for TODOS
        org-todo-keyword-faces
        '(("REFILE" . "red4")
          ("TODO" . "red")
          ("WAITING" . "orange")
          ("CANCELED" . (:strike-through t :foreground "DimGrey" :weight bold)))
        ;; Do not create a TOC
        org-export-with-toc nil
        ;; Do not number sections
        org-export-with-section-numbers nil
        ;; REFILE
        org-refile-targets '((nil :maxlevel . 9)
                             (org-agenda-files :maxlevel . 9))
        org-refile-use-outline-path 'full-file-path
        org-outline-path-complete-in-steps nil
        )

  ;;;;;; Capture templates
  (setq org-capture-templates
        '(("t"
           "todo"
           entry (file+headline org-default-notes-file "Tasks")
           "* REFILE %^{todo}\n %? \n %a")
          ("n"
           "note"
           entry (file+headline org-default-notes-file "Notes")
           "* %^{title}\n %?")))

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

  ;; ;; Allow emphasis markup in the middle of words
  ;; (setcar org-emphasis-regexp-components " \t('\"{[:alpha:]")
  ;; (setcar (nthcdr 1 org-emphasis-regexp-components) "[:alpha:]- \t.,:!?;'\")}\\")
  ;; (org-set-emph-re 'org-emphasis-regexp-components org-emphasis-regexp-components)

  ;; Strike-through for checked boxes
  (defface org-checkbox-done-text
    '((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)

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

  ;; Menu keybindings
  :general
  (spcleader
    "o"  '(:ignore t :which-key "Org")
    "oO" 'projectorg/go-to-inbox
    "oo" 'projectorg/go-to-notes
    "oa" 'org-agenda
    "oc" 'counsel-projectile-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
    "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)

  ;; Normal keybindings
  (:keymaps  'org-mode-map
   :states   'normal
   "RET"     'org-open-at-point
   "gt"      'org-mark-ring-goto
   "U"       'undo-tree-redo
   "<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)

  ;; Insert keybindings
  (:keymaps 'org-mode-map
   :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)

  ;; Pretty checkboxes
  :hook (org-mode . (lambda ()
                      (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)))

  ;; Use ivy for org-link
  :hook (org-mode . (lambda () (setq-local completing-read-function 'ivy-completing-read)))

  :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)))))

;;;;; Org Agenda

(use-package org-agenda
  :ensure nil
  :config
  (setq
   ;; Hide blocked todos from agenda
   org-agenda-dim-blocked-tasks 'invisible
   ;; Agenda window
   org-agenda-window-setup 'current-window
   org-agenda-restore-windows-after-quit t
   ;; Agenda for 10 days from 1 day before
   org-agenda-span 10
   org-agenda-start-day "-1d"
   org-agenda-include-diary t
   org-agenda-skip-scheduled-if-deadline-is-shown t
   org-agenda-tags-column -78
   org-agenda-start-with-follow-mode t
   org-agenda-todo-ignore-scheduled 'all
   org-agenda-skip-scheduled-if-done t
   org-agenda-skip-deadline-if-done t
   org-agenda-skip-deadline-prewarning-if-scheduled 3
   ;; org-agenda-sorting-strategy
   ;; '((agenda deadline-up priority-down)
   ;;   (todo priority-down category-keep)
   ;;   (tags priority-down category-keep)
   ;;   (search category-keep))
   )

  ;; Agenda keybindings
  :general
  (: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))

;;;;; 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
  ;; Set colors
  (setq org-priority-faces
        '((?A . "#ff5d38")
          (?B . "orange")
          (?C . "#98be65")))

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

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

;;;;; Outshine

(use-package outshine
  :general
  (:keymaps  'outshine-mode-map
   :states   'normal
   "<tab>"   'outshine-cycle
   "S-<tab>" 'outshine-cycle-buffer
   [(control return)] 'outshine-insert-heading
   "ð"       'outline-previous-visible-heading
   "ß"       'outline-next-visible-heading
   "Ð"       'outline-backward-same-level
   "ẞ"       'outline-forward-same-level
   "Þ"       'outline-up-heading
   "þ"       'outshine-kbd-M-<left>
   "®"       'outshine-kbd-M-<right>
   "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-completion-library 'org-ref-ivy-cite
        org-latex-pdf-process '("latexmk -shell-escape -bibtex -f -pdf %f")))

;;;;; Poly-org

;; (use-package poly-org)

;;;;; Org caldav

(use-package org-caldav
  :config
  (setq org-caldav-url "https://caldav.maximewack.com/maxx"
        org-caldav-inbox "~/Projects/caldav-in.org"
        org-caldav-files '("~/Projects/notes.org")
        org-icalendar-timezone "Europe/Paris"
        org-caldav-sync-direction 'cal->org
        org-caldav-sync-changes-to-org 'all)
        org-caldav-calendars '((:calendar-id "5b0bbb40-8725-3c71-3a3d-8951170cbee7"
                                :sync-direction 'cal->org)
                               (:calendar-id "94ad67a3-c712-9e0e-f729-96ec23ff9713"
                                :sync-direction 'cal->org)
                               (:calendar-id "4e3071f2-df7b-0aa4-41f9-f1789d744bd9"
                                :inbox "~/Projects/caldav-org.org"
                                :files org-agenda-files
                                :sync-direction 'org->caldav))
        )

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

(use-package projectile
  :config
  (projectile-clear-known-projects)
  (setq projectile-completion-system 'ivy))

;;;;; Projectorg
(use-package projectorg
  :load-path "~/Projects/projectorg"
  :demand
  :config
  (setq projectorg-projects-root "/home/maxx/Projects/"
        projectorg-org-dir "org/")

  ;; Capture template
  (add-to-list 'org-capture-templates
               `("pp"
                 "project"
                 entry (file+headline ,(concat projectorg-projects-root projectorg-org-dir "projects.org") "Projects")
                 ,(concat "* [[" projectorg-projects-root projectorg-org-dir "%^{project}.org][%^{project}]]\n")))
  (add-to-list 'org-capture-templates
               `("pc"
                 "cours"
                 entry (file+headline ,(concat projectorg-projects-root projectorg-org-dir "projects.org") "Cours")
                 ,(concat "* [[" projectorg-projects-root projectorg-org-dir "%^{project}.org][%^{project}]]\n")))
  (add-to-list 'org-capture-templates
               `("pr"
                 "requête"
                 entry (file+headline ,(concat projectorg-projects-root projectorg-org-dir "projects.org") "Requêtes")
                 ,(concat "* [[" projectorg-projects-root projectorg-org-dir "%^{project}.org][%^{project}]]\n")))
  (add-to-list 'org-capture-templates
               `("po"
                 "perso"
                 entry (file+headline ,(concat projectorg-projects-root projectorg-org-dir "projects.org") "Perso")
                 ,(concat "* [[" projectorg-projects-root projectorg-org-dir "%^{project}.org][%^{project}]]\n")))
  (add-to-list 'org-capture-templates
               `("pd"
                 "divers"
                 entry (file+headline ,(concat projectorg-projects-root projectorg-org-dir "projects.org") "Divers")
                 ,(concat "* [[" projectorg-projects-root projectorg-org-dir "%^{project}.org][%^{project}]]\n")))

  ;; (advice-add 'find-file :after 'projectorg/add-to-project-list))
  )

;;;;; Counsel-projectile

(use-package counsel-projectile
  :config
  (setq counsel-projectile-org-capture-templates
        `(("tp"
           "[${name}] Todo"
           entry (file+headline ,(concat projectorg-projects-root projectorg-org-dir "${name}.org") "Tasks")
           "* TODO %^{todo}\n %? \n %a")
          ("np"
           "[${name}] Note"
           entry (file+headline ,(concat projectorg-projects-root projectorg-org-dir "${name}.org") "Notes")
           "* %^{title} %t\n %?")))
  :general
  (spcleader
    "p"     '(:ignore t :which-key "Projectile")
    "pf"    'counsel-projectile-find-file
    "pb"    'counsel-projectile-switch-to-buffer
    "pp"    'counsel-projectile-switch-project
    "pg"    'counsel-projectile-grep
    "p SPC" '(lambda () (interactive) (find-file "~/Projects/org/projects.org"))))

;;;;; Skeletor

(use-package skeletor
  :config
  (setq skeletor-completing-read-function 'ivy-completing-read
        skeletor-user-directory "~/Projects/skeletons"
        skeletor--project-types nil)
  (skeletor-define-template "skel-Requete"
    :title "Requête"
    :no-license? t)
  (skeletor-define-template "skel-Elisp"
    :title "Elisp"))

;;;; Jump to definition

(use-package dumb-jump
  :config
  (setq dumb-jump-selector 'ivy)
  :general
  (spcleader
    "d" 'dumb-jump-go))

;;;; CSV mode

(use-package csv-mode)

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

(use-package lua-mode)

;;;;; Company-lua

(use-package company-lua)

;;;; ESS
;;;;; ESS

(use-package ess
  :config
  (setq ess-ask-for-ess-directory nil
        comint-scroll-to-bottom-on-input 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)

  (: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 "%>%")))

  (: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 "%>%")))

  (: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 (ess-mode . (lambda () (setq-local completing-read-function 'ivy-completing-read))))

;;;;; 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 ess-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
   "þ"      'markdown-hide-subtree
   "®"      '(lambda () (interactive)
              (markdown-show-children)
              (markdown-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)
  (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-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-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"      'quit-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
  :config
  (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
  :config
  (global-git-gutter-mode t))

;;;; Elpy

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

;;;; Slime

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

;;;; Flycheck

(use-package flycheck
  :config
  (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)

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

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

  ;; Mail accounts
  (cond ((equal (system-name) "hegp")
         (setq mu4e-maildir (expand-file-name "~/Mail/aphp")
               mu4e-get-mail-command "mbsync aphp"
               mu4e-refile-folder "/Local_archive"
               mu4e-user-mail-address-list '("maxime.wack@aphp.fr")
               mu4e-maildir-shortcuts
               '(("/Inbox"          . ?i)
                 ("/Local_archive"  . ?a)
                 ("/Trash"          . ?t)
                 ("/Junk"           . ?j)
                 ("/Sent"           . ?s))
               mu4e-compose-signature "Maxime Wack, MD, MSc
Assistant Hospitalo-Universitaire
Pôle Informatique et Santé Publique
Hôpital Européen Georges Pompidou
tel: 01 56 09 23 63"))
        ((equal (system-name) "laptop")
         (setq mu4e-maildir (expand-file-name "~/Mail/free")
               mu4e-user-mail-address-list '("maximewack@free.fr")
               mu4e-get-mail-command "mbsync free"
               mu4e-refile-folder "/Archives"
               mu4e-compose-signature "Maxime"))
        ((equal (system-name) "hegp-laptop")
         (setq mu4e-maildir (expand-file-name "~/Mail/free")
               mu4e-user-mail-address-list '("maximewack@free.fr")
               mu4e-get-mail-command "mbsync free"
               mu4e-refile-folder "/Archives"
               mu4e-compose-signature "Maxime")))

  ;; Options
  (setq mu4e-view-prefer-html t
        mu4e-update-interval 300
        mu4e-headers-auto-update t
        mu4e-compose-signature-auto-include t
        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
        ;; Required by mbsync
        mu4e-change-filenames-when-moving t
        message-kill-buffer-on-exit t
        mu4e-compose-dont-reply-to-self t
        mu4e-completing-read-function 'ivy-completing-read
        mu4e-split-view 'vertical
        mu4e-headers-visible-columns 110
        mu4e-headers-include-related nil
        mu4e-headers-skip-duplicates t
        mu4e-headers-results-limit 500
        mu4e-index-cleanup t
        mu4e-index-lazy-check nil
        mail-user-agent 'mu4e-user-agent)

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

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

  ;; Add action to view in browser
  (add-to-list 'mu4e-view-actions
               '("browser" . mu4e-action-view-in-browser) t)

  :general
  (: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-delete
   "U"      'mu4e-mark-unmark-all
   "X"      'mu4e-mark-execute-all
   "W"      'mu4e-headers-toggle-include-related
   "T"      '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)

  (: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"      'mu4e~view-quit-buffer
   "x"      'mu4e-view-mark-for-trash
   "a"      'mu4e-view-mark-for-refile
   "u"      'mu4e-view-mark-for-unmark
   "l"      'mu4e-view-mark-for-delete
   "U"      'mu4e-mark-unmark-all
   "X"      'mu4e-mark-execute-all
   "T"      '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-attachment-action))

;;;;; 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)
  ;; Mail accounts
  (cond ((equal (system-name) "laptop")
         (setq smtpmail-smtp-server "smtp.free.fr"
               user-mail-address "maximewack@free.fr"
               auth-sources '(password-store)))
        ((equal (system-name) "hegp-laptop")
         (setq smtpmail-smtp-server "smtp.free.fr"
               user-mail-address "maximewack@free.fr"
               auth-sources '(password-store)))
        ((equal (system-name) "hegp")
         (setq smtpmail-smtp-server "smtp.aphp.fr"
               user-mail-address "maxime.wack@aphp.fr"
               auth-sources '(password-store)
               smtpmail-smtp-service 25))))

;;;;; Org-mime

(use-package org-mime)

;;;;; Org-msg

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

;;;;; Org-mu4e

(use-package org-mu4e
  :demand
  :ensure nil
  :config
  (setq org-mu4e-convert-to-html t)

  :hook (mu4e-compose-mode . org-mu4e-compose-org-mode))

;;;;; Htmlize

(use-package htmlize)

;;;;; Gnus-dired

(require 'gnus-dired)

(defun gnus-dired-mail-buffers ()
  "Return a list of active message buffers."
  (let (buffers)
    (save-current-buffer
      (dolist (buffer (buffer-list t))
        (set-buffer buffer)
        (when (and (derived-mode-p 'message-mode)
                   (null message-sent-message-via))
          (push (buffer-name buffer) buffers))))
    (nreverse buffers)))

(setq gnus-dired-mail-mode 'mu4e-user-agent)

(add-hook 'dired-mode-hook 'turn-on-gnus-dired-mode)
