;; Configure emacs packages.
(require 'package)
(setq package-archives
      '(("gnu"   . "https://elpa.gnu.org/packages/")
        ("melpa" . "https://melpa.org/packages/")))
(package-initialize)
;; (package-refresh-contents)

(unless (package-installed-p 'use-package)
  (package-install 'use-package))
(require 'use-package)
(setq use-package-always-ensure t)

(setq inhibit-startup-screen t)

(savehist-mode 1)
(setq savehist-additional-variables '(kill-ring search-ring regexp-search-ring))

(global-set-key (kbd "C-x C-e") 'eval-region)

;; yank at cursor point instead of mouse
(setq mouse-yank-at-point t)

(setq column-number-mode t)
(setq ido-use-filename-at-point nil)

(use-package undo-tree
  :ensure t
  :after evil
  :diminish
  :config
  (evil-set-undo-system 'undo-tree)
  (global-undo-tree-mode 1))
(use-package evil
  :ensure t ;; install the evil package if not installed
  :init ;; tweak evil's configuration before loading it
  (setq evil-search-module 'evil-search)
  (setq evil-ex-complete-emacs-commands nil)
  (setq evil-vsplit-window-right t)
  (setq evil-split-window-below t)
  (setq evil-shift-round nil)
  (setq evil-want-C-u-scroll t)
  (setq evil-want-C-i-jump nil) ;; so that TAB is operational in org
  :config
  (evil-mode)
  (define-key evil-normal-state-map (kbd ", w") 'evil-window-vsplit))

(use-package rg
  :config
  (global-set-key (kbd "M-s g") 'rg)
  (global-set-key (kbd "M-s d") 'rg-dwim))

(use-package rustic
  :ensure
  :bind (:map rustic-mode-map
              ("C-c C-c l" . flycheck-list-errors)
              ("C-c C-c a" . lsp-execute-code-action)
              ("C-c C-c r" . lsp-rename)
              ("C-c C-c q" . lsp-workspace-restart)
              ("C-c C-c Q" . lsp-workspace-shutdown)
              ("C-c C-c s" . lsp-rust-analyzer-status))
  :config
  (setq lsp-eldoc-hook nil)
  (setq lsp-enable-symbol-highlighting nil)
  (setq lsp-signature-auto-activate nil)
  (setq rustic-flycheck-clippy-params "--message-format=json")
  (setq rustic-format-on-save t)
  (add-hook 'rustic-mode-hook 'rk/rustic-mode-hook))

(defun rk/rustic-mode-hook ()
  ;; so that run C-c C-c C-r works without having to confirm, but don't try to
  ;; save rust buffers that are not file visiting. Once
  ;; https://github.com/brotzeit/rustic/issues/253 has been resolved this should
  ;; no longer be necessary.
  (when buffer-file-name
    (setq-local buffer-save-without-query t)))

(use-package lsp-mode
  :ensure
  :commands lsp
  :custom
  ;; what to use when checking on-save. "check" is default, I prefer clippy
  (lsp-rust-analyzer-cargo-watch-command "clippy")
  (lsp-eldoc-render-all t)
  (lsp-idle-delay 0.6)
  (lsp-rust-analyzer-server-display-inlay-hints t)
  :config
  (add-hook 'lsp-mode-hook 'lsp-ui-mode))

(use-package lsp-ui
  :ensure
  :commands lsp-ui-mode
  :config (setq lsp-ui-peek-enable nil)
          (setq lsp-ui-doc-enable nil)
          (setq lsp-ui-doc-use-childframe nil)
          (setq lsp-ui-doc-header nil)
          (setq lsp-ui-doc-position 'top)
          (setq lsp-ui-doc-use-webkit nil)
  :custom (lsp-ui-peek-always-show t)
          (lsp-ui-sideline-show-hover nil)
          (lsp-ui-doc-enable nil)
  :bind (:map lsp-ui-mode-map
          ("M-." . lsp-ui-peek-find-definitions)
          ("M-," . lsp-ui-peek-jump-backward)
          ("M-r" . lsp-ui-peek-find-references)
          ("M-h" . lsp-ui-doc-show)
          ("M-l" . lsp-ui-doc-hide)
          ("M-j" . lsp-ui-imenu)
          ("M-k" . lsp-ui-sideline-apply-code-actions)))

(use-package company
  :ensure
  :custom
  (company-idle-delay 0.5) ;; how long to wait until popup
  ;; (company-begin-commands nil) ;; uncomment to disable popup
  :bind
  (:map company-active-map
              ("C-n". company-select-next)
              ("C-p". company-select-previous)
              ("M-<". company-select-first)
              ("M->". company-select-last))
  (:map company-mode-map
	("<tab>". tab-indent-or-complete)
	("TAB". tab-indent-or-complete)))

(use-package magit
  :init)

(use-package yasnippet
  :ensure
  :config
  (yas-reload-all)
  (add-hook 'prog-mode-hook 'yas-minor-mode)
  (add-hook 'text-mode-hook 'yas-minor-mode))

(defun company-yasnippet-or-completion ()
  (interactive)
  (or (do-yas-expand)
      (company-complete-common)))

(defun check-expansion ()
  (save-excursion
    (if (looking-at "\\_>") t
      (backward-char 1)
      (if (looking-at "\\.") t
        (backward-char 1)
        (if (looking-at "::") t nil)))))

(defun do-yas-expand ()
  (let ((yas/fallback-behavior 'return-nil))
    (yas/expand)))

(defun tab-indent-or-complete ()
  (interactive)
  (if (minibufferp)
    (minibuffer-complete)
    (if (or (not yas/minor-mode)
            (null (do-yas-expand)))
      (if (check-expansion)
        (company-complete-common)
        (indent-for-tab-command)))))

(use-package flycheck :ensure)

;; Please set your themes directory to 'custom-theme-load-path
(add-to-list 'custom-theme-load-path
             (file-name-as-directory "~/.emacs.d/replace-colorthemes"))
(add-to-list 'custom-theme-load-path "~/.emacs.d/themes")
(load-theme 'vim-colors t t)
(enable-theme 'vim-colors)

(define-advice evil-ex-hl-match-hook (:around (fn hl) add-priority-reset-hook)
    (or (funcall fn hl)
        (lambda (_ ov)
          (overlay-put ov 'priority 0))))
(set-face-attribute 'default nil :height 110)

;; Disable the menu.
(tool-bar-mode -1)
;; Enable transient mark mode.
(transient-mark-mode 1)

;; Highlight paired parentheses when cursor is over one.
(show-paren-mode 1)

(setq-default display-line-numbers-type 'absolute
              display-line-numbers-current-absolute t
              display-line-numbers-width 4
              display-line-numbers-widen t)

(add-hook 'text-mode-hook #'display-line-numbers-mode)
(add-hook 'prog-mode-hook #'display-line-numbers-mode)

(defun local/project-try-explicit (dir)
  "Find a super-directory of DIR containing a root file."
  (locate-dominating-file dir ".root"))

(defmethod project-root ((project string))
  project)

(add-hook 'project-find-functions
	  #'local/project-try-explicit)

(use-package dired-sidebar
             :bind (("C-x C-n" . dired-sidebar-toggle-sidebar))
             :ensure t
             :commands (dired-sidebar-toggle-sidebar)
             :init
             (add-hook 'dired-sidebar-mode-hook
                         (lambda ()
                         (unless (file-remote-p default-directory)
                             (auto-revert-mode))))
             :config
             (push 'toggle-window-split dired-sidebar-toggle-hidden-commands)
             (push 'rotate-windows dired-sidebar-toggle-hidden-commands)

             (setq dired-sidebar-subtree-line-prefix "__")
             (setq dired-sidebar-theme 'vscode)
             (setq dired-sidebar-use-term-integration t)
             (setq dired-sidebar-use-custom-font t))

(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-safe-themes
   '("d268b67e0935b9ebc427cad88ded41e875abfcc27abd409726a92e55459e0d01" default))
 '(package-selected-packages
   '(nord-theme yasnippet use-package undo-fu tommyh-theme rustic rg material-theme lsp-ui flycheck evil dired-sidebar company)))
(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.
 )
