* General Configuration

General configuration is configuration of vanilla Emacs. This includes making Emacs more minimal.

** Disable Error Bell

Disable error bell and visual bell. Visual bell would be nice on Linux, but on mac it is just annoying so I removed it temp.

#+begin_src emacs-lisp
  (setq ring-bell-function 'ignore)
  (setq visual-bell nil)
#+end_src

** Disable Dialog Box

Disables the dialog prompting box and instead prompts the user in the minibuffer.

#+begin_src emacs-lisp
(setq use-dialog-box nil)
#+end_src

** Relocate Custom File

Change location of custom file. This will stop *custom* from appending to the config file.

#+begin_src emacs-lisp
  (setq custom-file "~/.emacs.d/custom.el")
  (unless (file-exists-p custom-file)
      (make-empty-file custom-file))
  (load custom-file)
#+end_src

** Move Backup File

This moves the backup files so that Emacs doesn't clutter up directories with backup files.

#+begin_src emacs-lisp
(setq backup-directory-alist '(("." . "~/.emacs.d/backups/")))
#+end_src

** Time Startup

This function times the startup to tell you how long it took for the Emacs config to load.

#+begin_src emacs-lisp
(defun jm/display-startup-time ()
  (message "Emacs loaded in %.2f seconds with %d garbage collections."
           (float-time (time-subtract after-init-time before-init-time))
           gcs-done))

(add-hook 'emacs-startup-hook 'jm/display-startup-time)
#+end_src

** White Space

Various configuration relating to white-space.

#+begin_src emacs-lisp
  (setq-default electric-ident-inhibit t) ; Stop indentation of the previous line.
#+end_src

*** Tabs/Spaces

Disable tabs and replace them with a custom number of spaces.

#+begin_src emacs-lisp
  (setq-default indent-tabs-mode nil) ; Use spaces instead of tabs.
  (setq-default tab-width 4)
  (setq-default evil-shift-width tab-width)

  ; C Indentation
  (setq-default c-basic-offset 4)

  ; Yara Indentation
  (setq-default yara-indent-offset 4)
  (setq-default yara-indent-section 4)
#+end_src

*** Visualizing White Space

Add a nice visualization for tabs and spaces. This can be helpful to identify which is which quickly to avoid submitting poorly spaced code.

#+begin_src emacs-lisp
  (global-whitespace-mode)
  (setq whitespace-global-modes '(not org-mode dired-mode))
  (setq whitespace-style '(face tabs spaces tab-mark space-mark trailing))
  (custom-set-faces
    '(whitespace-tab ((t (:foreground "#384551"))))
    '(whitespace-space ((t (:foreground "#384551")))))


  (setq whitespace-display-mappings
    '((tab-mark 9 [187 9] [92 9])
      (space-mark 32 [183] [46])))
#+end_src

** SSH Remoting with Tramp

Below are a few configuration changes to avoid TRAMP freezes when attempting to SSH into another system with more complex config files.

#+begin_src emacs-lisp
(setq tramp-remote-shell "/bin/sh")
(setq tramp-remote-shell-login "-l")
(setq tramp-remote-shell-args "-c")
#+end_src

* General Packages

Emacs and packages. Pretty much a requirement.

** Setup package

Initialize *package* and setup package archives. This lets you install packages from other archives such as [[https://melpa.org/][melpa]].

#+begin_src emacs-lisp
  (require 'package)

  (setq package-archives '(("melpa" . "https://melpa.org/packages/")
                           ("org" . "https://orgmode.org/elpa/")
                           ("elpa" . "https://elpa.gnu.org/packages/")))

  (package-initialize)
  (unless package-archive-contents
    (package-refresh-contents))
#+end_src

** Use-package

Install use package for easier installation of other packages.

#+begin_src emacs-lisp
  (unless (package-installed-p 'use-package)
    (package-install 'use-package))

  (require 'use-package)
  (setq use-package-always-ensure t)
  (setq use-package-compute-statistics t)
#+end_src

Fixes path issue that occurs on mac.

#+begin_src emacs-lisp
  (use-package exec-path-from-shell
    :config
    (when (memq window-system '(mac ns x))
      (exec-path-from-shell-initialize)))
#+end_src

** Installed Packages

This is a list of installed packages not included in any other category.

*** Command Log Mode

Command Log Mode creates a window that logs all commands and corresponding keybindings.

#+begin_src emacs-lisp
(use-package command-log-mode
  :defer t
  :config (global-command-log-mode))
#+end_src

*** Magit

*Magit* adds several features to Emacs that make using git easier.

#+begin_src emacs-lisp
(use-package magit)
#+end_src

*** Helpful

*Helpful* is a package that improves the builtin Emacs help menus.

#+begin_src emacs-lisp
  (use-package helpful
    :config ; Set keybindings to call helpful instead of the default emacs help.
    (global-set-key (kbd "C-h f") #'helpful-callable)
    (global-set-key (kbd "C-h v") #'helpful-variable)
    (global-set-key (kbd "C-h k") #'helpful-key)
    (global-set-key (kbd "C-h x") #'helpful-command)

    ;; Lookup the current symbol at point. C-c C-d is a common keybinding for this in lisp modes.
    (global-set-key (kbd "C-c C-d") #'helpful-at-point)

    ;; Look up *F*unctions (excludes macros).
    (global-set-key (kbd "C-h F") #'helpful-function)

    ;; Syncing with ivy and counsel
    (setq counsel-describe-function-function #'helpful-callable)
    (setq counsel-describe-variable-function #'helpful-variable))
#+end_src

*** Perspective

*Perspective* is a package to help with managing buffers. It allows for multiple /workspaces/ or /perspectives/ which each contain their own sub list of buffers. 

#+begin_src emacs-lisp
(use-package perspective
  :bind (("C-x b" . persp-ivy-switch-buffer)
         ("C-x k" . persp-kill-buffer*))
  :custom (persp-mode-prefix-key (kbd "C-x w"))
  :init
  (persp-mode))
#+end_src

* Cosmetic

Packages that change the look of Emacs in some way.

** Cosmetic Configuration

Disable the useless features that make Emacs bloated.

#+begin_src emacs-lisp
  ; Disable startup message
  (setq inhibit-startup-message t)

  (scroll-bar-mode -1)   ; Disable scrollbar
  (tool-bar-mode -1)     ; Disable toolbar
  (tooltip-mode -1)      ; Disable tooltips
  (menu-bar-mode -1)     ; Disable menu-bar
  (set-fringe-mode 10)   ; Add gaps on left and right
  (setq scroll-margin 4) ; Scroll as cursor reaches bottom/top of page.
#+end_src

*** Change font

Pretty self explanatory.

#+begin_src emacs-lisp
  (defun jm/set-font-faces ()
      (set-face-attribute 'default nil :font "Fira Code Retina" :height 140))
#+end_src

Adding a fix for fonts when running Emacs as a daemon.

#+begin_src emacs-lisp
  (if (daemonp)
      (add-hook 'after-make-frame-functions
                (lambda (frame)
                  (with-selected-frame frame
                    (jm/set-font-faces))))
    (jm/set-font-faces))
#+end_src

** Doom Modeline

Use doom modeline to make the modeline look nicer.

#+begin_src emacs-lisp
    (use-package all-the-icons) ; requirement
    (use-package doom-modeline
      :init (doom-modeline-mode 1)
      :config
      (setq doom-modeline-height 45)
      (display-time))
#+end_src

In order to avoid missing icons, you should also install the package ~all-the-icons-install-fonts~ through the Emacs command line.

** Doom Themes

Install doom themes for better themes.

#+begin_src emacs-lisp
  (use-package doom-themes
    :init (load-theme 'doom-city-lights t))
#+end_src

** Rainbow Delimiters

Colors parenthesis for better lisp syntax highlighting.

#+begin_src emacs-lisp
  (use-package rainbow-delimiters
    :hook (prog-mode . rainbow-delimiters-mode))
#+end_src

** Line Numbers

This adds relative line numbers while excluding certain modes.

#+begin_src emacs-lisp
  ; Disable line numbers for certain modes
  (dolist (mode '(org-mode-hook
                  term-mode-hook
                  vterm-mode-hook
                  shell-mode-hook
                  eshell-mode-hook))
    (add-hook mode (lambda () (display-line-numbers-mode 0))))

  ; Enable relative line numbers
  (setq-default display-line-numbers-type 'visual)
  (global-display-line-numbers-mode t)
#+end_src

* Auto-completion

Packages associated with Emacs auto-completion. This does not include auto-completion from language servers just the auto-completion of commands etc.

** Counsel

Adds various completion functions used by Ivy.

#+begin_src emacs-lisp
  (use-package counsel
    :bind (("M-x" . counsel-M-x)
           ("C-x C-f" . counsel-find-file)
           :map minibuffer-local-map
           ("C-r" . counsel-minibuffer-history)))
#+end_src

** Ivy

Ivy is a basic auto-completion package that completes Emacs functions.

#+begin_src emacs-lisp
  (use-package ivy
    :diminish
    :bind (("C-s" . swiper)
           :map ivy-minibuffer-map
           ("TAB" . ivy-alt-done)	
           ("C-l" . ivy-alt-done)
           ("C-j" . ivy-next-line)
           ("C-k" . ivy-previous-line)
           :map ivy-switch-buffer-map
           ("C-k" . ivy-previous-line)
           ("C-l" . ivy-done)
           ("C-d" . ivy-switch-buffer-kill)
           :map ivy-reverse-i-search-map
           ("C-k" . ivy-previous-line)
           ("C-d" . ivy-reverse-i-search-kill))
    :config
    (ivy-mode 1))
#+end_src

** Ivy-rich

Install *Ivy-rich* for function info in Ivy auto complete.

#+begin_src emacs-lisp
  (use-package ivy-rich
    :init (ivy-rich-mode 1))
#+end_src

* Keybindings

Contains the configuration for any keybindings or packages relating to keybindings.

** General Configurations

Remap quit command to make it easier to rescue a buffer. With this function, escape will be used instead of *C-g*.

#+begin_src emacs-lisp
  (global-set-key (kbd "<escape>") 'keyboard-escape-quit)
#+end_src

** Packages

*** Which-key

Lists all possible keybindings off of prefix.

#+begin_src emacs-lisp
  (use-package which-key
    :init (which-key-mode)
    :diminish which-key-mode)
#+end_src

*** General

General allows you to setup a prefix key easily. This makes it really easy to setup a bunch of keybindings with ease.

#+begin_src emacs-lisp
  (use-package general
    :config
    (general-create-definer jm/leader-keys
      :keymaps '(normal insert visual emacs)
      :prefix "SPC"
      :global-prefix "C-SPC")

    (jm/leader-keys
     ; Example of a keybinding should be changed later
     "t" '(counsel-load-theme :which-key "Choose theme")
     "v" '(vterm :which-key "Open vterm terminal")
     "r" '(rename-buffer :which-key "Rename buffer")

     ; Org mode related keybindings
     "oa" '(org-agenda :which-key "Org agenda")

     ; Emacs related keybindings
     "er" '((lambda () (interactive) (load-file "~/.emacs")) :which-key "Reload emacs config")
     "es" '(eshell :which-key "Open eshell terminal")))
#+end_src

*** Evil

Evil is a package that adds vim keybindings to Emacs.

#+begin_src emacs-lisp
  ;; Setup vim keybindings with evil
  (use-package evil
    :init
    (setq evil-want-integration t)
    (setq evil-want-keybinding nil) ; replaced with evil collection
    (setq evil-want-C-u-scroll t)
    (setq evil-want-C-i-jump nil)
    :config
    (evil-mode 1)
    (define-key evil-insert-state-map (kbd "C-g") 'evil-normal-state)
    (define-key evil-insert-state-map (kbd "C-h") 'evil-delete-backward-char-and-join)

    ; Use visual line motions even outside of visual-line-mode buffers.
    (evil-global-set-key 'motion "j" 'evil-next-visual-line)
    (evil-global-set-key 'motion "k" 'evil-previous-visual-line)

    ; Modify which modes use vim keybindings.
    (evil-set-initial-state 'messages-buffer-mode 'normal)
    (evil-set-initial-state 'dashboard-mode 'normal))
#+end_src

**** Evil Collection

Evil collection is a package that replaces the bad ~evil-want-keybinding~ keybindings.

#+begin_src emacs-lisp
  (use-package evil-collection
    :after evil
    :config (evil-collection-init))
#+end_src

**** Undo-Tree

Undo tree's use is self explanatory. While the built-in Emacs undo system is fine for me, *undo-tree* is required as it fixes an issue with evil where you can't redo.

#+begin_src emacs-lisp
  ; Fix vim redo with undo tree
  (use-package undo-tree
    :after evil
    :config
    (evil-set-undo-system 'undo-tree)
    (setq undo-tree-history-directory-alist '(("." . "~/.emacs.d/undo")))
    (global-undo-tree-mode 1))
#+end_src

*** Hydra

Hydra is a package that implements a way to execute the same commands in quick succession.

#+begin_src emacs-lisp
  (use-package hydra :defer)
#+end_src

Setup easy changing of font size. This implements a zooming system to make text smaller or bigger quickly.

#+begin_src emacs-lisp
  (defhydra hydra-zoom (:timeout 4)
    ("j" text-scale-increase "in")
    ("k" text-scale-decrease "out")
    ("f" nil "finished" :exit t))
#+end_src

This keybinding needs to be added to general to give it a prefix.

#+begin_src emacs-lisp
  (jm/leader-keys
  "z" '(hydra-zoom/body :which-key "scale-text"))
#+end_src

* Dired

Dired is a built-in package in Emacs that allows for basic file navigation. While it serves its purpose, vanilla dired is far from a good file navigator. With some basic customization however, this can be changed.

#+begin_src emacs-lisp
  (use-package dired
    :ensure nil ; Melpa won't be able to find this package.
    :commands (dired dired-jump)
    :bind (("C-x C-j" . dired-jump))
    :custom ((dired-listing-switches "-ahgo"))
    :config
    (evil-collection-define-key 'normal 'dired-mode-map
      "h" 'dired-single-up-directory
      "l" 'dired-single-buffer))
#+end_src

** Dired Single

Vanilla dired opens a new buffer for every new directory it visits. When managing files, this will quickly fill up resulting in a ridiculous number of buffers. Though, single dired fixes this problem by instead modifying the current buffer when navigating through files.

#+begin_src emacs-lisp
  (use-package dired-single :after dired)
#+end_src

** All the Icons Dired

~all-the-icons-dired~ is a dired plugin that adds icons to each of the files.

#+begin_src emacs-lisp
  (use-package all-the-icons-dired
    :after dired
    :hook (dired-mode . all-the-icons-dired-mode))
#+end_src

** Hide Dotfiles

This hides all dotfiles in dired with the keybinding ~H~.

#+begin_src emacs-lisp
(use-package dired-hide-dotfiles
  :hook (dired-mode . dired-hide-dotfiles-mode)
  :config
  (evil-collection-define-key 'normal 'dired-mode-map
    "H" 'dired-hide-dotfiles-mode))
#+end_src

* Import Other Files

This is the section to include imports from other files.

#+begin_src emacs-lisp
  (defun jm/load-config-if-exists (file-path)
    (if (file-exists-p file-path)
        (org-babel-load-file file-path)
      (warn (concat "Failed to load config: " file-path))))

  (jm/load-config-if-exists "~/.emacs.d/org.org") ; Org-mode
  (jm/load-config-if-exists "~/.emacs.d/lsp.org") ; Language Server Protocol
  (jm/load-config-if-exists "~/.emacs.d/terminal.org") ; Emacs Terminal
  (jm/load-config-if-exists "~/.emacs.d/functions.org") ; Personal Elisp Functions
  (jm/load-config-if-exists "~/.emacs.d/email.org") ; Mu4e/SMTP Config

  ;; Load EXWM configuration if environment variable set.
  (let ((exwm-org-file "~/.emacs.d/exwm.org"))
    (when (and (file-exists-p exwm-org-file) (getenv "USING_EXWM"))
      (org-babel-load-file exwm-org-file)))
#+end_src
