* General Configuration

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

** Global Constants

Constants used throughout my emacs config.

#+begin_src emacs-lisp
(defconst jm/cloud-root "~/Nextcloud")
(defconst jm/notes-directory (expand-file-name "org" jm/cloud-root))
#+end_src

** 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

** Disable Docstring Warnings

#+begin_src emacs-lisp
(setq byte-compile-warnings '(not docstrings))
#+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

** 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 erc-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

** Updating PATH from User Shell

This package fixes issues with the path on MacOS by pulling the ~$PATH~ variable from the user's shell.

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

* Package Manager

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

* 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 "Maple Mono" :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
                  erc-mode-hook
                  mu4e-main-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

* 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

** 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
     ; Emacs related keybindings
     "r" '(rename-buffer :which-key "Rename buffer")
     "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

*** Evil Numbers

The /Evil Numbers/ package implements the ability to increment or decrement numbers as you would with vim using ~C-a~ and ~C-x~.

#+begin_src emacs-lisp
(use-package evil-numbers
  :after evil
  :config
  (evil-define-key '(normal visual) 'global (kbd "C-c =") 'evil-numbers/inc-at-pt)
  (evil-define-key '(normal visual) 'global (kbd "C-c -") 'evil-numbers/dec-at-pt)
  (evil-define-key '(normal visual) 'global (kbd "C-c C-=") 'evil-numbers/inc-at-pt-incremental)
  (evil-define-key '(normal visual) 'global (kbd "C-c C--") 'evil-numbers/dec-at-pt-incremental))
#+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

* Other Packages

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

** MacOS Environment Fix

When using emacs on MacOS, the environment variables are not synced properly and therefore require a separate package to fix this. In this case, this package is the ~exec-path-from-shell~.

#+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

** 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-switch-to-buffer*)
         ("C-x k" . persp-kill-buffer*))
  :custom (persp-mode-prefix-key (kbd "C-x w"))
  :init (persp-mode))
#+end_src

** Projectile

Projectile is a package for managing various /projects/ in emacs. It adds functionality to let you interact with various /projects/ such as quickly searching filenames, switching between all projects, grepping all files, etc.

#+begin_src emacs-lisp
(use-package projectile
  :bind-keymap
  ("C-x p" . projectile-command-map)
  :config
  (projectile-mode +1)
  :init
  (when (file-directory-p "~/Projects")
    (setq projectile-project-search-path '("~/Projects"))))
#+end_src

** Vertico

Vertico is a package that implements a drop-down like menu in the mini buffer allowing for much better searching.

#+begin_src emacs-lisp
(use-package vertico
  :init
  (vertico-mode))
#+end_src

When installing Vertico, the documentation mentions a few other packages that add some nice features that would come by default with something like /ivy/. I've added some descriptions of these below:

- ~savehist~ - One feature of Vertico that is really helpful is it's seamless integration with the built-in emacs package, ~savehist~, to save command history when navigating.
- ~marginalia~ - Similar to the definition of /marginalia/, this emacs package implements descriptions besides each option in Vertico completion. Some examples of this would be definitions for Elisp functions, more verbose file information, etc.
- ~orderless~ - By default, Vertico starts its completion from the start of the search the same way as default emacs completion. The ~orderless~ package changes this by implementing a nicer completion that searches for any similar options based on the provided search terms.
- ~consult~ - Adds a bunch of helpful search and navigation commands such as recursive file grepping, etc.

#+begin_src emacs-lisp
(use-package savehist
  :init
  (savehist-mode))

(use-package marginalia
  :after vertico
  :init
  (marginalia-mode))

(use-package orderless
  :custom
  (completion-styles '(orderless basic))
  (completion-category-overrides '((file (styles basic partial-completion)))))

(use-package consult
  :after vertico
  :config
  (jm/leader-keys 
    "pg" 'consult-grep
    "pf" 'consult-find))
#+end_src

** Helpful

*Helpful* is a package that improves the builtin Emacs help menus.  The config below installs helpful and sets the keybindings to call helpful functions instead of the default emacs help.

#+begin_src emacs-lisp
(use-package helpful
  :bind (("C-h f" . #'helpful-callable)
         ("C-h v" . #'helpful-variable)
         ("C-h k" . #'helpful-key)
         ("C-h x" . #'helpful-command)))

#+end_src

** Magit

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

#+begin_src emacs-lisp
(use-package magit
  :bind (("C-x g" . magit-status)
         ("C-x C-g" . magit-status))
  :config
  (jm/leader-keys "gc" 'magit-clone))
#+end_src

** Dashboard

The Emacs dashboard package provides a nice dashboard when first starting up emacs.

#+begin_src emacs-lisp
(use-package dashboard
  :init
  (setq initial-buffer-choice (lambda () (get-buffer-create "*dashboard*"))
        dashboard-startup-banner 'logo
        dashboard-icon-type 'nerd-icons
        dashboard-set-file-icons t
        dashboard-set-heading-icons t
        dashboard-items '((projects . 5)
                          (recents . 5)
                          (agenda . 5)))
  :config
  (set-face-attribute 'dashboard-items-face nil :font "Maple Mono" :height 140)
  (dashboard-setup-startup-hook))
#+end_src

** Ledger

Ledger is a Unix program that implements a finance tracking system or /ledger/. To implement this into emacs, you can install the ~ledger-mode~ emacs package.

#+begin_src emacs-lisp
(use-package ledger-mode
  :mode ("\\.ledger\\'")
  :config
  (setq ledger-report-use-strict t
        ledger-master-file (expand-file-name "Ledger/toc.ledger" jm/cloud-root)
        ledger-accounts-file (expand-file-name "Ledger/accounts.ledger" jm/cloud-root))
  (setq ledger-reports
        `(("bal" ,(format "%%(binary) -f %s bal" ledger-master-file))
          ("budget" ,(format "%%(binary) -f %s --budget -p 'this month' bal Expenses" ledger-master-file))
          ("account" ,(format "%%(binary) -f %s reg %%(account)" ledger-master-file))
          ("monthly bal" ,(format "%%(binary) -f %s bal -p 'this month'" ledger-master-file))
          ("daily bal" ,(format "%%(binary) -f %s bal -p 'today'" ledger-master-file)))))
#+end_src

** Alert

Alert is another library that better implements system notifications through emacs. As I use both MacOS and Linux, notifications don't work out of the box for both systems. Using alert, I can change this by selecting a working notify system for each OS.

#+begin_src emacs-lisp
(use-package alert
  :config
  (setq alert-default-style
        (if (eq system-type 'darwin)
            'osx-notifier
          'libnotify)))
#+end_src

* Builtin Package Config
** 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
      "T" 'dired-create-empty-file))
#+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
** ERC

ERC is a builtin package that adds IRC chatting functionality to emacs.

#+begin_src emacs-lisp

;; Shotcuts for general
(jm/leader-keys 
  "cc" '(erc-tls :which-key "Connect to IRC over TLS")
  "cb" '(erc-switch-to-buffer :which-key "Switch IRC buffers"))

(use-package erc
  :ensure nil
  :defer t
  :custom
  (erc-nick "random936")
  (erc-track-exclude-types '("JOIN" "NICK" "PART" "QUIT" "MODE"
                             "353" "324" "329" "332" "333" "353" "477"))
  (erc-autojoin-channels-alist '((".*\.libera\.chat" "#emacs" "#gentoo" "#systemcrafters")))
  (erc-fill-column 120)
  (erc-fill-function 'erc-fill-static)
  (erc-fill-static-center 20)
  (erc-kill-buffer-on-part t)
  (erc-kill-queries-on-quit t)
  (erc-kill-server-buffer-on-quit t)
  :config
  (add-to-list 'erc-modules 'notifications)
  ;; Fix for perspective.el not adding ERC buffers to active perspective.
  (add-hook 'erc-join-hook (lambda (&rest args)
                             (persp-add-buffer (current-buffer)))))
#+end_src

*** ERC Extensions

To highlight each nickname with a different color, I can use the ~erc-hl-nicks~ package. I can also use the ~erc-image~ package to render images sent by other users over IRC.

#+begin_src emacs-lisp
(use-package erc-hl-nicks
  :after erc
  :config (add-to-list 'erc-modules 'hl-nicks))

(use-package erc-image
  :after erc
  :config
  (setq erc-image-inline-rescale 300)
  (add-to-list 'erc-modules 'image))
#+end_src

*** ERC Alert Integration

Alert is a notification system that works with MacOS, however it is not integrated by default. To fix this, you need to create a function to hook with the ERC text matching.

#+begin_src emacs-lisp
(defun jm/erc-alert-integration (match-type nick message)
  (alert message :title (format "%s in %s" nick (buffer-name)) :category 'erc))

(add-hook 'erc-text-matched-hook 'jm/erc-alert-integration)
#+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/functions.org") ; Personal Elisp Functions
  (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/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
