(defconst dd/using-native-comp-p (fboundp 'native-comp-available-p))
(when dd/using-native-comp-p
  (setq comp-async-query-on-exit t)
  (setq comp-async-jobs-number 8)
  (setq comp-async-report-warnings-errors nil)
  (setq comp-deferred-compilation t))
(setq redisplay-dont-pause t)
(setq jit-lock-defer-time 0)
(setq fast-but-imprecise-scrolling t)
(setq make-backup-files nil)
(setq create-lockfiles nil)

;; A trick for faster startup is to just disable GC for the init phase
;;; See: https://github.com/nilcons/emacs-use-package-fast#a-trick-less-gc-during-startup
(setq gc-cons-threshold 64000000)
(add-hook 'after-init-hook #'(lambda ()
                               ;; restore after startup
                               (setq gc-cons-threshold 800000)))

(defun http-download-verify-and-exec (url sha256-hash name func)
  (let ((actual-hash ""))
    (with-temp-buffer
      ;; Somewhat not documented function. Based on https://emacs.stackexchange.com/a/38482
      ;; The problem is that url-retrieve-synchronously prints the HTTP headers at
      ;; the top, which are, since they include time, non-deterministic and thus cannot
      ;; be used for hashing.
      (url-insert-file-contents url)
      (setq actual-hash (secure-hash 'sha256 (current-buffer)))
      (unless (string= sha256-hash actual-hash)
	(error "Unexpected hash for %s: Got %s, expected %s" name actual-hash sha256-hash))
      func)))

(defvar bootstrap-version)
(let ((bootstrap-file
       (expand-file-name "straight/repos/straight.el/bootstrap.el" user-emacs-directory))
      (bootstrap-version 5)
      (install-hash ""))
  (unless (file-exists-p bootstrap-file)
    (http-download-verify-and-exec
     "https://raw.githubusercontent.com/raxod502/straight.el/develop/install.el"
     "5bbeee903a90a0fda88a6b8516697c121400facb36a2c349e9447a53baef154e"
     "straight's install.el"
     (lambda ()
       (goto-char (point-max))
       (eval-print-last-sexp))))
  (load bootstrap-file nil 'nomessage))

(setq straight-use-package-by-default t)
(straight-use-package 'use-package)

; Visual things
(defvar emacs-font "SourceCodePro:style=Light-7")
(add-to-list 'default-frame-alist `(font . ,emacs-font))
(set-face-attribute 'default t :height 150 :font emacs-font)
(tool-bar-mode -1)
(menu-bar-mode -1)
(toggle-scroll-bar -1)
(setq inhibit-startup-screen t)

;; We cannot exactly use use-package, so we just download it "manually".
(let* ((theme-dir (expand-file-name "themes" user-emacs-directory))
       (theme-file (expand-file-name "weyland-yutani-theme.el" theme-dir)))
  (unless (file-exists-p theme-file)
    (unless (file-exists-p theme-dir)
      (make-directory theme-dir))
    (http-download-verify-and-exec
     "https://raw.githubusercontent.com/jstaursky/weyland-yutani-theme/246410e1c03f7d8d8e76102f7c5e3cda83acb36b/weyland-yutani-theme.el"
     "6593a0a7e46710e25f9b9caf9888106c93230bd20f9af87c5fc883a98b187253"
     "weyland-yutani-theme.el"
     (lambda ()
       (write-file theme-file))))
  (add-to-list 'custom-theme-load-path theme-dir)
  (load-theme 'weyland-yutani t))

(use-package rainbow-delimiters
  :straight t
  :config
  (add-hook 'prog-mode-hook
	    #'rainbow-delimiters-mode))
(use-package hl-todo
  :straight t
  :config
  (add-hook 'prog-mode-hook
	    #'hl-todo-mode))
(global-hl-line-mode 1)
(use-package nlinum
  :straight t
  :config
  (add-hook 'prog-mode-hook
            (lambda ()
              (nlinum-mode 1))))
(add-hook 'prog-mode-hook
	  (lambda ()
	    (show-paren-mode 1)
	    (setq show-parens-delay 0)))

(use-package ivy
  :straight t
  :config
  (defvar ivy-use-virtual-buffers t)
  (ivy-mode 1))

(setq enable-recursive-minibuffers t)

; This function allows us to exit EVIL states with C-c
; (https://www.emacswiki.org/emacs/Evil#toc16)
(defun escape (prompt)
  (cond ((or (evil-insert-state-p) (evil-normal-state-p) (evil-replace-state-p) (evil-visual-state-p)) [escape])
        (t (kbd "C-g"))))
(use-package evil
  :init
  (setq evil-want-keybinding nil)
  :config
  (define-key key-translation-map (kbd "C-c") 'escape)
  (evil-mode 1))
(use-package evil-collection
  :after evil
  :ensure t
  :config
  (evil-collection-init))
; Vim-like buffer navigation
(global-set-key (kbd "C-h") 'windmove-left)
(global-set-key (kbd "C-l") 'windmove-right)
(global-set-key (kbd "C-k") 'windmove-up)
(global-set-key (kbd "C-j") 'windmove-down)

(use-package rainbow-delimiters
  :config
  (add-hook 'prog-mode-hook
	    #'rainbow-delimiters-mode))
(use-package highlight-parentheses
  :straight t
  :config
  (highlight-parentheses-mode))
(use-package smartparens
  :straight t
  :config
  (smartparens-global-mode t))
(use-package undo-tree
  :straight t
  :config
  (global-undo-tree-mode))

(use-package hl-todo
  :config
  (add-hook 'prog-mode-hook
	    #'hl-todo-mode))
(global-hl-line-mode 1)

(setq-default indent-tab-mode t)
(setq tab-width 4)

(use-package perspective
  :bind
  ("C-x C-b" . (lambda (arg)
		 (interactive "P")
		 (if (fboundp 'persp-bs-show)
		     (persp-bs-show arg)
		     (bs-show "all"))))
  :config
  (message "Persp-mode")
  (persp-mode))

;; mu4e config
(unless (string= (system-name) "miku")
  ; I don't need mu4e on my desktop
  (load-file (expand-file-name "mu4e.el" user-emacs-directory))
  (use-package mu4e
    :straight t
    :config
    (ptw/init-mu4e)))

(use-package calfw
  :straight (calfw
	     :host github
	     :repo "kiwanami/emacs-calfw"
	     :files ("calfw.el" "calfw-cal.el")))

;; Org mode stuff
;(use-package org-evil
;    :straight t)
(use-package graphviz-dot-mode
    :straight t)
(use-package org
  :straight t
  :bind
  ("C-x P" . (lambda ()
	       (interactive)
	       (org-babel-execute-src-block)
	       (org-redisplay-inline-images)))
  :config
  (org-babel-do-load-languages
   'org-babel-load-languages
   '((dot . t)))
  (add-hook 'org-mode-hook
	    (lambda ()
	      (local-set-key
	       (kbd "C-x q")
	       (lambda ()
		 (interactive)
		 (org-present-quit)))
	      (local-set-key
	       (kbd "C-x p")
	       (lambda ()
		 (interactive)
		 (org-present))))))
(use-package org-present
  :straight (org-present
	     :host github
	     :repo "rlister/org-present"
	     :files ("org-present.el"))
  :config
  (add-hook 'org-present-mode-hook
	    (lambda ()
	      (org-present-big)
	      (org-display-inline-images)
	      (org-present-hide-cursor)
	      (org-present-read-only)
	      (org-hide-block-all)

	      ; Disable evil, but bind left (prev) and right (next)
	      (turn-off-evil-mode)
	      (local-set-key
	       (kbd "l")
	       (lambda ()
		 (interactive)
		 (org-present-next)
		 ;; NOTE: Workaround for images not being shown wen
		 ;;       the slide has been changed
		 (org-redisplay-inline-images)))
		  (local-set-key
	       (kbd "h")
	       (lambda ()
		 (interactive)
		 (org-present-prev)
		 ;; NOTE: Workaround for images not being shown wen
		 ;;       the slide has been changed
		 (org-redisplay-inline-images)))

	      ;; Disable the modeline. But save it before so that we
	      ;; can restore it
	      (set (make-local-variable 'saved-mode-line-format) mode-line-format)
	      (setq mode-line-format nil)))
  (add-hook 'org-present-mode-quit-hook
	    (lambda ()
	      (org-present-small)
	      (org-remove-inline-images)
	      (org-present-show-cursor)
	      (org-present-read-write)
	      (org-show-all)
	      (turn-on-evil-mode)

	      (local-unset-key (kbd "h"))
	      (local-unset-key (kbd "l"))

	      ;; Restore the modeline.
	      ;; NOTE: We need to call redraw-display or else the modeline
	      ;;       won't be complete
	      (setq mode-line-format saved-mode-line-format)
	      (redraw-display))))

;; Development
(use-package tide
  :straight t
  :config
  (defun setup-tide-mode ()
    (interactive)
    (tide-setup)
    (tide-hl-identifier-mode +1))
  (add-hook 'typescript-mode-hook #'setup-tide-mode)
  (add-hook 'web-mode-hook
	    (lambda ()
	      (when (string-equal "tsx" (file-name-extension buffer-file-name))
		(setup-tide-mode))))
  (add-to-list 'auto-mode-alist '("\\.tsx\\'" . web-mode)))
(use-package nix-mode
  :straight t)
(use-package go-mode
  :straight t)

(use-package json-mode
  :straight t)

(use-package rust-mode
  :straight t)

;; Debugging
(use-package explain-pause-mode
  :straight
  (explain-pause-mode
   :type git
   :host github
   :repo "lastquestion/explain-pause-mode")
  :config
  (explain-pause-mode))