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

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

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

;; Disable package-selected-packages
(defun package--save-selected-packages (&rest opt) nil)

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

;; Kill all unmodified buffers
(defun maxx/kill-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
    "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))

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

  ;; 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
   "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

;; eshell-mode-map is not populated outside of eshell
;; So we need to define bindings in a hook
(defun maxx/eshell-keys ()
  (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"
  (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
  (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)
  ;; 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))

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

;;;; 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-tabnine

(use-package company-tabnine
  ;; install binaries with company-tabnine-install-binaries
  :demand)

;;;;; 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 t
        company-tooltip-align-annotations t
        company-minimum-prefix-length 2)
  (add-to-list 'company-backends '(company-tabnine) t)

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

;;;; Project management

;;;;; Projectile

(use-package projectile
  :config
  (projectile-clear-known-projects)
  (add-to-list 'projectile-project-root-files "notes.org")
  (setq projectile-completion-system 'ivy))

;;;;; Projectorg
(use-package projectorg
  :load-path "~/Projects/projectorg"
  :demand
  :hook (find-file . projectorg/add-to-project-list))

;;;;; Counsel-projectile

(use-package counsel-projectile
  :config
  (setq counsel-projectile-org-capture-templates
        '(("pt"
           "[${name}] Todo"
           entry (file+headline "${root}/notes.org" "Tasks")
           "* TODO %^{todo}\n %? \n %a")
          ("pn"
           "[${name}] Note"
           entry (file+headline "${root}/notes.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/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)

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

;;;; Slime

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

;;;; Flycheck

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

;;;; 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-agenda-files (directory-files-recursively "~/Projects" "\.org$")
        org-default-notes-file "~/Projects/notes.org"
        ;; 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-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 600
        ;; 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
        ;; 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 %?")
          ("C"
           "cheatsheet"
           entry (file+headline org-default-notes-file "Cheatsheets")
           "* %^{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)))

  ;; Project mode
  (add-to-list 'org-capture-templates
               '("p"
                 "project"
                 entry (file+headline "~/Projects/projects.org" "Projects")
                 "* [[%^{project}/notes.org][%^{project}]] %^g\n%^{TYPE}p %?\n"))

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

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

  ;; 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 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
   "ð"       '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 mobile

(use-package org-mobile
  :ensure nil
  :config
  (setq org-mobile-directory "/ssh:maxx@home:orgmobile"
        org-mobile-inbox-for-pull "/ssh:maxx@home:orginbox.org"))

;;;;; Poly-org

(use-package poly-org)

;;;; 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 "Dr 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")))

  ;; 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)
  (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")
         (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-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)
