;;; Package Management
;;;; Bootstrap straight.el
(defvar bootstrap-version)
(let ((bootstrap-file
       (expand-file-name "straight/repos/straight.el/bootstrap.el" user-emacs-directory))
      (bootstrap-version 5))
  (unless (file-exists-p bootstrap-file)
    (with-current-buffer
        (url-retrieve-synchronously
         "https://raw.githubusercontent.com/raxod502/straight.el/develop/install.el"
         'silent 'inhibit-cookies)
      (goto-char (point-max))
      (eval-print-last-sexp)))
  (load bootstrap-file nil 'nomessage))

;;;; Select And Install Managed Straight Packages
(defvar straight-package-list
  '(auto-complete
    company
    company-box
    darktooth-theme
    dap-mode
    doom-modeline
    ebuild-mode
    fill-column-indicator
    flycheck
    gdscript-mode
    helm
    lsp-mode
    lua-mode
    magit
    mood-one-theme
    no-littering
    outshine
    prettier-js
    rustic
    silkworm-theme
    solarized-theme
    suscolors-theme
    tide
    use-package
    web-mode
    xresources-theme
    yaml-mode
    zenburn-theme
    ))

(dolist (package straight-package-list)
  (straight-use-package package))

;;;; Install Packages Directly From Repositories
(use-package arc-dark-theme
  :straight (:host github :repo "cfraz89/arc-dark-theme"))

(use-package ligature
  :straight (:host github :repo "mickeynp/ligature.el"))

;;; General Emacs Settings
;;;; Memory Management
(setq gc-cons-threshold 100000000)
(setq read-process-output-max (* 1024 1024)) ;; 1mb

;;;; Extra search paths
(add-to-list 'load-path "~/.emacs.d/lisp/")

;;;; Do Not Litter
(require 'no-littering)

;;;;; Backups
(setq backup-directory-alist
      `((".*" . ,(no-littering-expand-var-file-name "backup/"))))
(setq auto-save-file-name-transforms
      `((".*" ,(no-littering-expand-var-file-name "auto-save/") t)))

;;;;; Customizations
(setq custom-file (no-littering-expand-etc-file-name "custom.el"))
(if (file-exists-p custom-file) (load custom-file))

;;;; User Interface
(setq frame-title-format (concat "%b - Emacs " emacs-version))
(setq inhibit-splash-screen t)
(menu-bar-mode -1)
(tool-bar-mode -1) 
(when (display-graphic-p) (scroll-bar-mode -1))
(column-number-mode t)
(setq mouse-wheel-scroll-amount '(1 ((shift) . 1) ((control) . nil)))
(setq mouse-wheel-progressive-speed t)
(setq warning-minimum-level :error)

;;;;; Mode Line
(setq doom-modeline-buffer-file-name-style 'buffer-name)
(doom-modeline-mode 1)

;;;;; Font and Theme
;;(setq-frame-font "firacode 8" nil t)
(add-to-list 'default-frame-alist '(font . "firacode-8"))
(setq custom-safe-themes t)

(setq solarized-use-variable-pitch nil
      solarized-scale-outline-headlines nil
      solarized-scale-org-headlines nil)

(when (display-graphic-p)
  (load-theme 'zenburn)
  (setq zenburn-scale-org-headlines t))

;;;; Editing
(setq-default fill-column 80
              indent-tabs-mode nil
              truncate-lines t
              tab-width 4)
(setq yank-excluded-properties t)
              
;;; Text Modes
;;;; Text Mode
(add-hook 'text-mode-hook
	  (lambda ()
	    (turn-on-auto-fill)
	    (flyspell-mode 1)))

;;; Programming Modes
;;;; General
(defvar indent-width 2 "Preferred indentation width for all configured programming modes")
(setq-default company-tooltip-align-annotations t)

(defun setup-prog-mode ()
  "Custom setup function for prog mode"
  (interactive)
  (show-paren-mode 1)
  (company-mode))
(add-hook 'prog-mode (lambda () (setup-prog-mode)))

;;;; C / C++
(setq-default c-default-style "stroustrup"
	      c-basic-offset indent-width)

(defun setup-c-mode ()
  "Custom setup function for C/C++ modes"
  (interactive)
  (lsp))

(add-hook 'c-mode-hook 'setup-c-mode)
(add-hook 'c++-mode-hook 'setup-c-mode)

;;;; Rust
(setq rustic-lsp-server 'rust-analyzer)
(setq rustic-indent-offset indent-width)

;;;; Web
;;;;; Formatting
(setq-default web-mode-code-indent-offset indent-width
              web-mode-attr-value-indent-offset indent-width
              web-mode-markup-indent-offset indent-width
              web-mode-css-indent-offset indent-width
              typescript-indent-level indent-width
              js-indent-level indent-width
              css-indent-offset indent-width
              web-mode-auto-quote-style nil
              web-mode-auto-close-style nil)

;;;;; TIDE Mode (Typescript IDE)
(defun setup-tide-mode ()
  "Setup function for tide."
  (interactive)
  (tide-setup)
  (flycheck-mode +1)
  (setq flycheck-check-syntax-automatically '(save mode-enabled))
  (eldoc-mode +1)
  (tide-hl-identifier-mode +1)
  (company-mode +1))

;;;;; Web Mode
(add-to-list 'auto-mode-alist '("\\.[jt]sx\\'" . web-mode))
(defun setup-web-mode ()
  "Setup function for web-mode."
  (interactive)
  (when (string-match-p "[tj]sx" (file-name-extension buffer-file-name))
    (setup-tide-mode)))

;;;;; Hooks
(add-hook 'js-mode-hook #'setup-tide-mode)
(add-hook 'typescript-mode-hook #'setup-tide-mode)
(add-hook 'js-mode-hook 'prettier-js-mode)
(add-hook 'typescript-mode-hook (lambda () (setup-tide-mode)))
(add-hook 'web-mode-hook (lambda () (setup-web-mode)))

;;;; Python
(add-hook 'python-mode-hook
	  (lambda ()
	    (setq indent-tabs-mode t)
	    (setq tab-width indent-width)
	    (setq python-indent indent-width)))

;;;; Emacs Lisp
(add-hook 'emacs-lisp-mode-hook
	  (lambda ()
	    (setup-prog-mode)
        ;; Use outshine mode for init file
        (when (buffer-file-name)
	      (when (file-equal-p user-init-file buffer-file-name)
	        (outshine-mode)
	        (outline-hide-body)))))
(add-hook 'ielm-mode-hook 'setup-prog-mode)

;;; Tramp
(setq tramp-default-method "ssh")

;;; Version Control
(setq vc-follow-symlinks t)
(global-set-key (kbd "C-x g") 'magit-status)

;;; Programming Ligatures
(setq prog-ligatures '("++" "--" "&&" "||"      ; Arithmetic
                       "+=" "-=" "*=" "/="      ; Arithmetic assignment
                       "%=" "|=" "&=" "^="
                       "->" "=>" "::"           ; Scope
                       "==" "!=" "<=" ">="      ; Comparison
                       "//" "///" "/*" "*/"     ; Comments
                       "\n" "\\"                ; Escaped characters
                       "<<" "<<<" ">>" ">>>"    ; Shifts
                       "<<=" ">>="))            ; Shift assignment

(setq rust-ligatures '(".." "..." "..="))       ; Ranges

(setq html-ligatures '("</" "/>" "</>"          ; Tags
                       "<!--" "-->"             ; Comments
                       "**" "===" "!==" "?."))  ; JavaScript

(setq lisp-ligatures '(";;"))                   ; Comments

(ligature-set-ligatures 'prog-mode prog-ligatures)
(ligature-set-ligatures 'rustic-mode rust-ligatures)
(ligature-set-ligatures '(web-mode html-mode js-mode typescript-mode)  html-ligatures)
(ligature-set-ligatures 'emacs-lisp-mode lisp-ligatures)
(global-ligature-mode)