;; .emacs --- Emacs customizations

;;; Commentary:
;;
;; My Emacs customizations.  Is there more to say?
;;
;; Packages:
;;
;; ac-emoji
;; ace-window
;; company
;; emms
;; emms-player
;; emojify
;; flycheck
;; helm
;; highlight-parentheses
;; image+
;; magit
;; markdown-mode
;; mic-paren
;; modalka-mode
;; multiple-cursors
;; nlinum
;; org-plus
;; projectile-mode

;;; Code:

(let ((minver "24.1"))
  (when (version< emacs-version minver)
    (error "Your Emacs is too old -- this config requires v%s or higher" minver)))

(setq gc-cons-threshold (* 511 1024 1024))
(setq gc-cons-percentage 0.5)
(run-with-idle-timer 5 t #'garbage-collect)

(when (>= emacs-major-version 24)
  (require 'package)
  (setq-default
   package-archives
   '(("gnu" . "https://elpa.gnu.org/packages/")
     ("melpa" . "https://melpa.org/packages/")
     ("org" . "https://orgmode.org/elpa/")))
  (package-initialize))

;;; Enable debug during loading.
;; (setq debug-on-error t)

(defvar emacs-cache-folder "~/.cache/emacs/"
  "Cache folder is everything we do not want to track together
  with the configuration files.")
(if (not (file-directory-p emacs-cache-folder))
    (make-directory emacs-cache-folder t))

;; General Modifications
(setq inhibit-splash-screen t)
(menu-bar-mode -1)
(tool-bar-mode -1)
;; (scroll-bar-mode -1)
(column-number-mode 1)
(set-frame-font "DejaVu Sans Mono")
(setq-default tab-width 2)
(global-auto-revert-mode t)
(setq confirm-kill-emacs #'y-or-n-p)	;Asks if you wish to leave emacs
(setq-default org-src-fontify-natively t)	;syntax highlighting in org-modesource blocks
(setq browse-url-browser-function 'eww-browse-url)
(setq visible-bell nil)
(setq fill-column 80)
(setq echo-keystrokes 0.1)
;;; Show matching parenthesis
(show-paren-mode 1)
;;; By default, there’s a small delay before showing a matching parenthesis. Set
;;; it to 0 to deactivate.
(setq show-paren-delay 0)
(setq show-paren-when-point-inside-paren t)
(setq-default ftp-program "sftp")
(setq-default vs-display-status nil)
(setq tab-always-indent 'complete)
(setq initial-scratch-message "")


;; indetn
;; You may need to get rid of the -default on the indent ones
(setq-default js-indent-level 2)
(setq-default js2-indent-level 2)
(setq-default js2-basic-offset 2)
(setq-default js2-strict-trailing-comma-warning nil) ;I don't care about commas
(setq-default typescript-indent-level 2)
(setq-default indent-tabs-mode nil)
(setq-default jsx-indent-level 2)
(setq-default css-indent-offset 2)


(setq backup-by-copying t      ; don't clobber symlinks
   backup-directory-alist
	 '(("." . "~/.backups"))    ; don't litter my fs tree
   delete-old-versions t
   kept-new-versions 6
   kept-old-versions 2
   version-control t)       ; use versioned backups

(add-hook 'minibuffer-exit-hook
      '(lambda ()
         (let ((buffer "*Completions*"))
           (and (get-buffer buffer)
                (kill-buffer buffer)))))

;; For some reason I think this loads images faster
(setq imagemagick-enabled-types t)

;; Removes trailing whitespace before saving.
(add-hook 'before-save-hook (lambda ()
			      (delete-trailing-whitespace)))

;; Thou shall use 2 spaces indenting
;; (setq typescript-indent-level 2)

;; Enable a line at the 80 character column for certain modes
(setq fci-rule-column 80)

;; Enable some good modes when editing source files
;; (add-hook 'hl-line-mode-hook
;;           (lambda ()
;;             (set-face-background 'hl-line "#c1dde6")
;;             (set-face-attribute 'region nil :background "LightSkyBlue1")))

(add-hook 'prog-mode-hook
	        (lambda ()
            (smartparens-mode 1)
	          (flycheck-mode 1)
            (hl-line-mode 1)))

(add-hook 'haskell-mode-hook
          (lambda ()
            (flycheck-mode -1)))

(add-hook 'html-mode-hook
	        (lambda ()
	          (flycheck-mode 1)
            (flyspell-mode -1)
            (hl-line-mode 1)))

(add-hook 'image-mode-hook 'imagex-sticky-mode)

;; Lets not forget the text modes!
(add-hook 'text-mode-hook
	  (lambda ()
	    ;; (column-enforce-mode 1)
	    ;; (nlinum-mode 1)
            ;; (modalka-mode 1)
	    (auto-fill-mode 1)
	    (flyspell-mode 1)
            (hl-line-mode 1)))

(add-hook 'markdown-mode-hook
	  (lambda ()
	    ;; (column-enforce-mode 1)
	    (auto-fill-mode 1)
	    ;; (nlinum-mode 1)
            ;; (modalka-mode 1)
	    (flyspell-mode 1)
            (hl-line-mode 1)))

(defun org-table-copy-down-no-inc (&optional arg)
  "Copy the previous cell's value without incrementing.
ARG is needed for `kill-word'."
  (interactive "p")
  (kill-word arg)
  (yank)
  (org-return)
  (org-table-blank-field)
  (yank)
  (org-table-align))


(use-package org
  :bind (:map org-mode-map
              ("C-S-<down>" . org-table-copy-down-no-inc)))

;; (use-package org-journal
;;   :init
;;   (setq-default org-journal-dir "~/personal/journal"))


(add-hook 'latex-mode-hook
	  (lambda ()
	    (fci-mode 1)
	    ;; (nlinum-mode 1)
	    (flycheck-mode 1)
	    (column-enforce-mode 1)
	    (auto-fill-mode 1)
	    (flyspell-mode 1)))

(add-hook 'erc-mode-hook
	  (lambda ()
	    (erc-notify-mode 1)
	    (flyspell-mode 1)))

;; Enable M-RET to add another comment line. This is mainly for typing long
;; explainations that take more than 1 line. For example, this comment...
;; Note: Since the other languages I use have things like /* */, they don't
;; need this feature.
(add-hook 'emacs-lisp-mode-hook
					'(lambda () (local-set-key (kbd "M-RET") 'comment-indent-new-line)))
(add-hook 'common-lisp-mode-hook
					'(lambda () (local-set-key (kbd "M-RET") 'comment-indent-new-line)))
(add-hook 'lisp-mode-hook
					'(lambda () (local-set-key (kbd "M-RET") 'comment-indent-new-line)))
(add-hook 'sh-mode-hook
					'(lambda () (local-set-key (kbd "M-RET") 'comment-indent-new-line)))
(add-hook 'R-mode-hook
					'(lambda () (local-set-key (kbd "M-RET") 'comment-indent-new-line)))

;; Make backtab go backwards for links, like any normal person would want it
(add-hook 'eww-mode-hook
					'(lambda ()
						 (local-set-key (kbd "<backtab>") 'shr-previous-link)
						 (local-set-key (kbd "&") 'eww-external-browser-seamonkey)))

(defvar mode-line-cleaner-alist
  `((smartparens-mode . " ()")
    (eldoc-mode . "")
    (abbrev-mode . "")
    (undo-tree-mode . " U")
    (ivy-mode . " Ɩ")
    (flycheck-mode . " ✔")
    (flyspell-mode . " s✔")
    ;; Major modes
    (lisp-interaction-mode . "λ")
    (emacs-lisp-mode . "Eλ")
    (eshell-mode . "ξ")
    (haskell-mode . "Hλ")
    (purescript-mode . "PS")
    (clojurescript-mode . "CLJS")
    (clojure-mode . "Cλ")
    (javascript-mode . "JS")
    (racket-mode . "Rλ")
    (erc-mode . "Ɛ")
    (calc-mode . "π")))


(defun clean-mode-line ()
  (interactive)
  (dolist (cleaner mode-line-cleaner-alist)
    (let* ((mode (car cleaner))
	   (mode-str (cdr cleaner))
	   (old-mode-str (cdr (assq mode minor-mode-alist))))
      (when old-mode-str
	(setcar old-mode-str mode-str))
      ;; major mode
      (when (eq mode major-mode)
	(setq mode-name mode-str)))))

(add-hook 'after-change-major-mode-hook 'clean-mode-line)


;; Personal Keybindings
(global-set-key (kbd "C-x o") 'ace-window)
(global-set-key (kbd "M-c") 'comment-region)
(global-set-key (kbd "M-C") 'capitalize-word)
(global-set-key (kbd "M-u") 'uncomment-region)
(global-set-key (kbd "M-U") 'upcase-word)
(global-set-key (kbd "C-x &") 'calendar)
(global-set-key (kbd "M-g c") 'avy-goto-char)
(global-set-key (kbd "M-g M-c") 'avy-goto-char)
(global-set-key (kbd "M-g t") 'avy-goto-char-2)
(global-set-key (kbd "M-g M-t") 'avy-goto-char-2)
(global-set-key (kbd "M-g l") 'avy-goto-char-in-line)
(global-set-key (kbd "M-g M-l") 'avy-goto-char-in-line)
(global-set-key (kbd "M-g c") 'iy-go-to-char)
(global-set-key (kbd "M-g C") 'iy-go-to-char-backward)
(global-set-key (kbd "M-g ;") 'iy-go-to-or-up-to-continue)
(global-set-key (kbd "M-g :") 'iy-go-to-or-up-to-continue-backward)
(global-set-key (kbd "M-g f") 'avy-goto-line)
(global-set-key (kbd "M-g M-f") 'avy-goto-line)
(global-set-key (kbd "M-g w") 'avy-goto-word-1)
(global-set-key (kbd "M-g M-w") 'avy-goto-word-1)
;; (global-set-key (kbd "M-G G") 'magit-status)
;; (global-set-key (kbd "C-|") 'pop-global-mark) ;return to last cursor position
(global-set-key (kbd "C-x B") 'list-buffers)
(global-set-key (kbd "C-x C-b") 'ido-switch-buffer)
(global-set-key (kbd "C-x b") 'ido-switch-buffer)
(global-set-key (kbd "M-o") 'ace-window)
(global-set-key (kbd "M-h") 'ido-switch-buffer)
(global-set-key (kbd "M-k") 'ido-kill-buffer)
(add-hook 'org-mode-hook
					'(lambda () (local-set-key (kbd "M-h") 'ido-switch-buffer)))
;; replace `compose-mail' keybinding
(global-unset-key (kbd "C-x m"))
(global-set-key (kbd "C-x m m") 'compose-mail)
;; C-x M for Multicursor or Music (for emms controls)
;; Notice for the music controls, previous and next are upper case!
(global-set-key (kbd "C-x m d") 'mc/mark-all-dwim) ;d for dwim
(global-set-key (kbd "C-x m l") 'mc/mark-next-lines) ;l for lines
(global-set-key (kbd "C-x m a") 'mc/mark-all-like-this) ;a for all
(global-set-key (kbd "C-x m n") 'mc/mark-next-like-this) ;n for next
(global-set-key (kbd "C-x m m") 'mc/mark-more-like-this-extended) ;m for more
(global-set-key (kbd "C-x M p") 'emms-pause) ;p for pause
(global-set-key (kbd "C-x M P") 'emms-previous) ;P for previous
(global-set-key (kbd "C-x M N") 'emms-next) ;N for next
(global-set-key (kbd "C-x M s") 'emms-show) ;s for show
(global-set-key (kbd "C-x M f") 'emms-play-file) ;play (f)ile
(global-set-key (kbd "C-x M D") 'emms-play-directory) ;play (D)irectory
(global-set-key (kbd "C-x M v") 'emms-playlist-mode-go) ;(v)iew playlist
(global-set-key (kbd "C-x E a") 'emojify-apropos-emoji) ; For easy emoji finding
;; (global-set-key (kbd "M-d") 'forward-delete-word-no-kill-ring)
;; (global-set-key (kbd "M-<backspace>") 'backward-delete-word-no-kill-ring)
(global-set-key (kbd "M-D") 'kill-word)
(global-set-key (kbd "M-S-<backspace>") 'backward-kill-word)
(global-set-key (kbd "M-<SPC>") 'mark-sexp)
(global-set-key (kbd "M-g m") 'magit-status)
;; (global-set-key (kbd "C-m") 'replace-char)
(global-set-key (kbd "C-x C-l") 'display-line-numbers-mode)
(global-set-key (kbd "C-x p w") 'pwd)
(global-set-key (kbd "<home>") 'beginning-of-buffer)
(global-set-key (kbd "<end>") 'end-of-buffer)

(use-package emojify
  :hook ((text-mode     . emojify-mode)
         (org-mode      . emojify-mode)
         (markdown-mode . emojify-mode)
         (erc-mode      . emojify-mode)))


;; (use-package ledger-mode
;;   :bind
;;   (("C-c C-e" . ledger-jentry)
;;    :map ledger-mode-map
;;    ("C-c C-j" . ledger-run-command))
;;   :init
;;   (add-to-list 'auto-mode-alist '("\\.dat\\'" . hledger-mode))
;;   (setq-default hledger-currency-string "$"
;;                 hledger-jfile "~/personal/money/finances/2020.dat"))

(use-package ivy
  :bind
  ("C-s" . swiper-isearch)
  ("C-r" . swiper-isearch-backward)
  ("C-c C-r" . ivy-resume)
  ("C-x C-f" . counsel-find-file)
  ("C-x b" . counsel-switch-buffer)
  ("C-x C-b" . counsel-switch-buffer)
  ("M-x" . counsel-M-x)
  ("M-y" . 'counsel-yank-pop)
  ("<f1> f" . counsel-describe-function)
  ("<f1> v" . counsel-describe-variable)
  ("<f1> l" . 'counsel-find-library)
  ("<f1> a" . 'counsel-apropos)
  ("<f2> i" . 'counsel-info-lookup-symbol)
  ("<f2> u" . 'counsel-unicode-char)
  ("<f2> j" . 'counsel-set-variable)
  ("C-c v" . 'ivy-push-view)
  ("C-c V" . 'ivy-pop-view)
  ("C-x p g" . 'counsel-git-grep)
  ("C-x p f" . counsel-git)                                        ;this is basically projectile-find-file
  :config
  (ivy-mode 1)
  (setq ivy-use-virtual-buffers t
        enable-recursive-minibuffers t)
  (define-key ivy-minibuffer-map (kbd "<return>") 'ivy-alt-done))

(use-package flx)


;;; Others
(setq-default ispell-program-name "/usr/pkg/bin/aspell")

(use-package slime-autoloads
  :config
  (setq-default inferior-lisp-program "/usr/local/bin/sbcl"))
(use-package slime
  :config
  (slime-setup)
  (setq slime-contribs '(slime-fancy)))
(slime-setup '(slime-company))

;; eshell
;; Run "alias sudo 'eshell/sudo $*'" sudo to work right
(use-package em-tramp
  :init
  (setq-default eshell-prefer-lisp-functions t
                eshell-prefer-lisp-variables t
                password-cache t ; enable password caching
                password-cache-expiry 300 ; for 5 minutes (time in secs)
                tramp-histfile-override "/dev/null"))


;;; Email
;;; setup for use with mbsync in maildir format

(defun kev-mark-as-disposed-and-read (&optional number data)
  (interactive)
  (wl-summary-dispose)
  (wl-summary-mark-as-read))

(defun kev-mark-as-disposed-and-read-region (beg end)
  (interactive "r")
  (wl-summary-dispose-region beg end)
  (wl-summary-mark-as-read-region beg end))

(setq user-mail-address "kevin.bloom@posteo.net"
      smtpmail-smtp-user "kevin.bloom@posteo.net"
      smtpmail-local-domain "posteo.de"
      smtpmail-default-smtp-server "posteo.de"
      smtpmail-smtp-server "posteo.de"
      smtpmail-smtp-service 587
      smtpmail-stream-type  'starttls
      message-send-mail-function 'smtpmail-send-it)

(use-package elmo
  :config
  (elmo-search-register-engine
   'mairix 'local-file
   :prog "mairix"
   :args '(pattern)
   :charset 'utf-8)
  (setq elmo-search-default-engine 'mairix
        elmo-passwd-storage-type 'auth-source))
(use-package wl
  :bind
  (:map wl-summary-mode-map
        ("d" . kev-mark-as-disposed-and-read)
        ("r d" . kev-mark-as-disposed-and-read-region))
  :hook
  (wl-folder-check-entity-hook wl-folder-open-all)
  :config
  (setq wl-quicksearch-folder "[]"
        wl-summary-line-format "%n%T%P %Y/%M/%D (%W) %h:%m %t%[%25(%c %f%) %] %s"
        wl-summary-width 150
        wl-message-ignored-field-list '("^.*:")
        wl-message-visible-field-list '("^To:"
                                        "^Cc:"
                                        "^From:"
                                        "^Subject:"
                                        "^Date:"
                                        "^Content-Disposition:")
        wl-message-sort-field-list '("^From:"
                                     "^Subject:"
                                     "^Date:"
                                     "^To:"
                                     "^Cc:"
                                     "^Content-Disposition:")
        wl-fcc "./Users/kev/Maildir/posteo/sent/" ;prefixing with '.' means maildir
        wl-fcc-force-as-read t

        wl-smtp-posting-server "posteo.de"
        wl-smtp-posting-port 587
        wl-smtp-connection-type 'starttls
        wl-smtp-authenticate-type "plain"
        wl-smtp-posting-user "kevin.bloom@posteo.net"))

(custom-set-variables
 ;; custom-set-variables was added by Custom.
 ;; If you edit it by hand, you could mess it up, so be careful.
 ;; Your init file should contain only one such instance.
 ;; If there is more than one, they won't work right.
 '(custom-enabled-themes '(gruvbox-dark-soft))
 '(custom-safe-themes
   '("72ed8b6bffe0bfa8d097810649fd57d2b598deef47c992920aef8b5d9599eefe" "2ff9ac386eac4dffd77a33e93b0c8236bb376c5a5df62e36d4bfa821d56e4e20" default))
 '(package-selected-packages
   '(gruvbox-theme janet-mode lua-mode flycheck smartparens company-emojify company-ledger emojify slime slime-company ace-window avy counsel flx ivy magit multiple-cursors smex swiper use-package)))
(custom-set-faces
 ;; custom-set-faces was added by Custom.
 ;; If you edit it by hand, you could mess it up, so be careful.
 ;; Your init file should contain only one such instance.
 ;; If there is more than one, they won't work right.
 )
