This is a collection of dotfiles and scripts for my bspwm setup
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

48 KiB

Ricemacs, an Emacs Configuration

Initial setup

These commands need to be run after the first startup.

Irony mode

M-x irony-install-server RET

All the icons

M-x all-the-icons-install-fonts RET

Lexical Binding

  ;;; -*- lexical-binding: t; -*-

Global Variables

Variables for directories, leader keys, etc.

  (defvar dot-emacs-dir (directory-file-name (file-truename user-emacs-directory))
	"Directory base.")

  (defvar dot-etc-dir (concat dot-emacs-dir "/etc")
	"Directory for non-volatile storage.")

  (defvar dot-cache-dir (concat (getenv "XDG_CACHE_HOME") "/emacs")
	"Directory for cache data.")

  (defvar dot/leader-key "SPC"
	"Leader prefix key.")

  (defvar dot/leader-alt-key "M-SPC"
	"Alternative leader prefix key, used for Insert and Emacs states.")

  (defvar dot/localleader-key "SPC m"
	"Local leader prefix key, for 'major-mode' specific commands.")

  (defvar dot/localleader-alt-key "M-SPC m"
	"Alternative local leader prefix key, used for Insert and Emacs states.")

  (defvar dot/shell "/bin/zsh"
	"Command interpreter binary path.")

Customizations

Store customize file separately, don't freak out when it's not found.

  (setq custom-file (concat dot-etc-dir "/custom.el"))
  (load custom-file 'noerror)

Set font.

  (set-face-attribute 'default nil :height 90 :family "DejaVu Sans Mono")

Package Management

Ensure

Ensures packages are installed by default.

  (require 'use-package-ensure)
  (setq use-package-always-ensure t)

Auto update

Update pending updates of installed packages at startup. https://github.com/rranelli/auto-package-update.el

  (use-package auto-package-update
	:custom
	(auto-package-update-delete-old-versions t)
	(auto-package-update-hide-results t)
	(auto-package-update-last-update-day-path (concat dot-cache-dir "/last-package-update-day"))
	:config
	(auto-package-update-maybe))

Compile

Automatically compile all packages. https://github.com/emacscollective/auto-compile

  (use-package auto-compile
	:custom (load-prefer-newer t)
	:config
	(auto-compile-on-load-mode)
	(auto-compile-on-save-mode))

Packages

Install and configure packages.

General

  (use-package hybrid-reverse-theme
	:load-path "~/code/elisp/emacs-hybrid-reverse"
	:custom (load-theme 'hybrid-reverse t))

  (use-package all-the-icons
	:defer t)

  (use-package which-key
	:hook (emacs-startup . which-key-mode)
	:custom
	(which-key-add-column-padding 1)
	(which-key-max-display-columns nil)
	(which-key-min-display-lines 5)
	(which-key-sort-order 'dot/which-key-prefix-then-key-order-alpha)
	(which-key-sort-uppercase-first nil))

  (use-package general)

  (use-package selectrum
	:hook (emacs-startup . selectrum-mode))

  (use-package prescient
	:after selectrum
	:config
	(setq prescient-filter-method '(literal regexp fuzzy))
	(setq prescient-save-file (concat dot-cache-dir "/prescient-save.el"))
	(prescient-persist-mode))

  (use-package selectrum-prescient
	:after (selectrum prescient)
	:config
	(selectrum-prescient-mode))

  (use-package avy
	:defer t)

  (use-package hungry-delete
	:config (global-hungry-delete-mode))

  (use-package smart-tabs-mode
	:config
	(smart-tabs-add-language-support latex latex-mode-hook
	  ((latex-indent-line . 4)
	   (latex-indent-region . 4)))
	(smart-tabs-insinuate 'c 'c++ 'java 'python 'latex))

Evil

Evil mode and related packages.

  (use-package undo-tree)
  (use-package goto-chg)

  (use-package evil
 :after (undo-tree goto-chg)
 :custom
 (evil-search-module 'evil-search)
 (evil-ex-complete-emacs-commands nil)
 (evil-vsplit-window-right t)
 (evil-split-window-below t)
 (evil-shift-round nil)
 (evil-want-C-u-scroll t)
 ;; Do not set half cursor in operator state
 (evil-operator-state-cursor 'box)
 ;; Needed by evil-collection
 (evil-want-integration t)
 (evil-want-keybinding nil)
 :config (evil-mode))

  (use-package evil-collection
 :after evil
 :custom
 (evil-collection-company-use-tng nil)
 (evil-collection-key-blacklist (list dot/leader-key dot/localleader-key
									  dot/leader-alt-key dot/localleader-alt-key
									  "M-h" "M-j" "M-k" "M-l"))
 (evil-collection-setup-minibuffer t)
 :config (evil-collection-init))

  (use-package evil-nerd-commenter
 :defer t
 :after evil)

Telephone Line

Emacs mode line replacement.

  (use-package telephone-line
	:custom
	(telephone-line-lhs
	 '((evil   . (telephone-line-evil-tag-segment))
	   (accent . (telephone-line-erc-modified-channels-segment
				  telephone-line-process-segment
				  telephone-line-buffer-segment))
	   (nil    . (telephone-line-projectile-segment))))
	:config (telephone-line-mode))

NeoTree

Provides Emacs with a file tree.

  (use-package neotree
	:after all-the-icons
	:custom
	(neo-theme (if (display-graphic-p) 'icons 'arrow))
	(neo-autorefresh nil)
	(neo-dont-be-alone t)
	(neo-mode-line-type 'none)
	(neo-show-hidden-files t)
	(neo-vc-integration '(face))
	:hook (neotree-mode . dot/hook-disable-line-numbers))

Centaur Tabs

Places buffers as tabs in a bar at the top.

  (use-package centaur-tabs
	:after all-the-icons
	:demand
	:custom
	(centaur-tabs-height 38)
	(centaur-tabs-modified-marker "•")
	(centaur-tabs-set-icons t)
	(centaur-tabs-set-modified-marker t)
	(centaur-tabs-style "slant")
	:hook
	((eshell-mode
	  help-mode
	  helpful-mode
	  neotree-mode
	  occur-mode
	  org-roam-backlinks-mode
	  shell-mode)
	 . centaur-tabs-local-mode)
	:config
	(centaur-tabs-headline-match)
	(centaur-tabs-mode))

Projectile

Project manager.

  (use-package projectile
	:defer t
	:custom
	(projectile-cache-file (concat dot-cache-dir "/projectile.cache"))
	(projectile-completion-system 'default)
	(projectile-enable-caching t)
	(projectile-indexing-method 'hybrid)
	(projectile-known-projects-file (concat dot-cache-dir "/projectile-bookmarks.eld"))
	(projectile-project-search-path '("~"))
	(projectile-sort-order 'recentf))

Org Packages

Org ToC

Generate table of contents without exporting.

  (use-package toc-org
	:defer t)
Org Roam

Setup org-roam.

  (use-package org-roam
	:hook (emacs-startup . org-roam-mode)
	:hook (org-roam-backlinks-mode . dot/hook-disable-line-numbers)
	:hook (org-roam-backlinks-mode . dot/hook-disable-mode-line)
	:config
	(setq org-roam-directory (concat (file-name-directory org-directory) "org/"))
	(setq org-roam-verbose nil)
	(setq org-roam-completion-system 'default)
	(org-roam-mode))

Enable Roam-Protocol, needed to process org-protocol:// links

  (use-package org-roam-protocol
	:ensure nil ; org-roam-protocol.el is part of org-roam
	:after org-roam)

Setup org-roam-server.

  (use-package simple-httpd
	:after org-roam)

  (use-package org-roam-server
	:after (org-roam simple-httpd)
	:config
	(setq org-roam-server-host "127.0.0.1")
	(setq org-roam-server-port 8080)
	(setq org-roam-server-network-arrows "from")
	(setq org-roam-server-style
		  (concat
		   "button#toggle-preview { margin: 4px; }"
		   "div#view-menu { margin: 4px; }"
		   "div#controls { right: 4px; left: 4px; bottom: 4px; }"
		   "button#toggle-list-type-button { margin: 0 4px; }"
		   "label#colormode { transform: translate(-25%, 0); }"
		   "label.toggle-off.btn-sm { padding-left: 0px; }"
		   )))
Org Exporters
  ;; HTML exporter
  (use-package htmlize
	:defer t
	:custom (org-export-html-postamble nil))
  ;org-export-html-postamble-format @ToDo

  ;; Github flavored Markdown exporter
  (use-package ox-gfm
	:defer t)

Completion

Autocomplete packages (includes code completion and snippets).

Company
  (use-package company
	:defer t
	:custom
	(company-idle-delay 0.2)
	(company-minimum-prefix-length 2)
	(company-tooltip-align-annotations 't)
	:hook
	((c-mode-common
	  emacs-lisp-mode
	  latex-mode
	  org-mode
	  php-mode
	  shell-mode
	  shell-script-mode)
	 . company-mode)
  )
Flycheck

On the fly syntax checking.

  (use-package flycheck
	:defer t
	:hook
	((c-mode-common
	  emacs-lisp-mode
	  latex-mode
	  org-mode
	  php-mode
	  shell-mode
	  shell-script-mode)
	 . flycheck-mode))

  ;; For .el files which are intended to be packages
  (use-package flycheck-package
	:after flycheck
	:config
	(add-to-list 'flycheck-checkers 'flycheck-emacs-lisp-package)
	(flycheck-package-setup))
LSP
  (use-package lsp-mode
	:commands lsp
	:after which-key
	:hook
	((c-mode         ; clangd
	  c++-mode       ; clangd
	  php-mode)      ; nodejs-intelephense
	 . lsp-deferred)
	:custom
	(lsp-auto-guess-root t)
	(lsp-clients-clangd-args '("--compile-commands-dir=build" "-j=2" "--background-index" "--log=error"))
	(lsp-enable-xref t)
	(lsp-intelephense-storage-path (concat dot-cache-dir "/lsp-cache"))
	(lsp-keep-workspace-alive nil)
	(lsp-prefer-flymake nil)
	(lsp-session-file (concat dot-cache-dir "/lsp-session-v1"))
	:config

	;; Enable which-key descriptions
	(dolist (leader-key (list dot/leader-key dot/leader-alt-key))
	  (let ((lsp-keymap-prefix (concat leader-key " l")))
		(lsp-enable-which-key-integration)))
	)

  (use-package company-lsp
	:commands company-lsp
	:after (company lsp-mode)
	:custom
	(company-transformers nil)
	(company-lsp-async t)
	(company-lsp-cache-candidates nil)
	(company-lsp-enable-snippet t)
	:config (push 'company-lsp company-backends))

  (use-package lsp-ui
	:commands lsp-ui-mode
	:after (flycheck lsp-mode)
	:custom
	(lsp-ui-doc-border (face-foreground 'default))
	(lsp-ui-doc-enable nil)
	(lsp-ui-doc-header t)
	(lsp-ui-doc-include-signature t)
	(lsp-ui-doc-position 'top)
	(lsp-ui-doc-use-childframe t)
	(lsp-ui-flycheck-enable t)
	(lsp-ui-flycheck-list-position 'right)
	(lsp-ui-flycheck-live-reporting t)
	(lsp-ui-peek-enable nil)
	(lsp-ui-sideline-enable nil))
YASnippet
  (use-package yasnippet
	:defer t
	:hook
	((fundamental-mode
	  prog-mode
	  text-mode)
	 . yas-minor-mode)
	:custom
	(yas-prompt-functions '(yas-completing-prompt))
	(yas-snippet-dirs (list (concat dot-emacs-dir "/snippets")))
	:config (yas-reload-all))

  (use-package yasnippet-snippets
	:after yasnippet)
C/C++

Irony requires M-x irony-install-server.

  (use-package irony
	:hook
	((c-mode
	  c++-mode)
	 . irony-mode)
	:hook (irony-mode . irony-cdb-autosetup-compile-options)
	:init (setq irony-user-dir (concat dot-cache-dir "/irony/"))
	:config
	(push 'glsl-mode irony-supported-major-modes)

	;; Compile the irony-server binary if it doesnt exist
	(unless (file-exists-p (concat irony-user-dir "bin/irony-server"))
	  (call-interactively 'irony-install-server)))

  (use-package company-irony
	:after (company irony)
	:config (push 'company-irony company-backends))

  (use-package company-c-headers
	:after company
	:config (push 'company-c-headers company-backends))
  ;; company-irony-c-headers
Org Roam Completion

Completion for Org-roam files using its title.

  (use-package company-org-roam
	:after (company org-roam)
	:config (push 'company-org-roam company-backends))

PHP

  (use-package php-mode
	:defer t
	:hook
	(php-mode
	 . (lambda () (progn
					(setq indent-tabs-mode t)
					(setq lsp-ui-doc-enable t)))))

Prettify

  (use-package dashboard
	:demand
	:custom
	(initial-buffer-choice (lambda () (get-buffer "*dashboard*")))
	(dashboard-banner-logo-title "GNU Emacs master race!")
	(dashboard-center-content t)
	(dashboard-set-file-icons t)
	(dashboard-set-footer nil)
	(dashboard-set-heading-icons t)
	(dashboard-show-shortcuts t)
	(dashboard-startup-banner 'logo)
	(dashboard-items '((projects . 10)
					   (bookmarks . 5)
					   (recents . 5)))
	:hook (dashboard-mode . dot/hook-disable-line-numbers)
	:config (dashboard-setup-startup-hook))

  ;; A better *help* buffer
  (use-package helpful
	:hook (helpful-mode . dot/hook-disable-line-numbers))

  (use-package rainbow-mode
	:hook (prog-mode . rainbow-mode))

  (use-package rainbow-delimiters
	:hook (prog-mode . rainbow-delimiters-mode))

  (use-package org-bullets
	:hook (org-mode . org-bullets-mode))

  ;; Cmake syntax highlighting
  (use-package cmake-mode
	:defer t)

  ;; Shader syntax highlighting
  (use-package glsl-mode
	:defer t)

  ;; Mark code after the 80 column range
  (use-package column-enforce-mode
	:hook (prog-mode . column-enforce-mode)
	:custom (column-enforce-comments nil))

Possible modern replacement for column-enforce-mode: https://github.com/laishulu/hl-fill-column

RSS

  (use-package elfeed
	:defer t
	:custom
	(elfeed-db-directory (concat dot-cache-dir "/elfeed"))
	(elfeed-enclosure-default-dir "~/downloads/")
	(elfeed-search-filter "@6-months-ago +unread")
	(elfeed-search-clipboard-type 'CLIPBOARD)
	(elfeed-search-title-max-width 100)
	(elfeed-search-title-min-width 30)
	(elfeed-search-trailing-width 55)
	(elfeed-show-unique-buffers t)
	:config
	(load-file (concat dot-etc-dir "/elfeed-feeds.el"))
	:hook (elfeed-search-mode . dot/hook-disable-line-numbers)
	:hook (elfeed-show-mode   . dot/hook-disable-line-numbers))

General

  ;; Columns start at 1
  (setq column-number-indicator-zero-based nil)

  ;; Custom thems, do not ask if safe
  (setq custom-safe-themes t)

  ;; Dired move to trash
  (setq delete-by-moving-to-trash t)

  ;; Scrolling
  (setq scroll-conservatively 1)
  (setq mouse-wheel-scroll-amount '(5))
  (setq mouse-wheel-progressive-speed nil)

  ;; Parenthesis, set behavior
  (setq show-paren-delay 0)
  (setq show-paren-style 'mixed)

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

  ;; Set undo limit, measured in bytes
  (setq-default undo-limit 400000)
  (setq-default undo-strong-limit 3000000)
  (setq-default undo-outer-limit 12000000)

  ;; Enable line numbers
  (global-display-line-numbers-mode)

  ;; C++ syntax highlighting for .h files
  (add-to-list 'auto-mode-alist '("\\.h\\'" . c++-mode))

  ;; When in the GUI version of Emacs, enable pretty symbols
  (when window-system (global-prettify-symbols-mode t))

  ;; Set the frame title
  (setq frame-title-format
		`("%b"
		  (:eval
		   (if (buffer-file-name)
			   (concat
				(if (buffer-modified-p) " •" nil)
				" ("
				(abbreviate-file-name
				 (directory-file-name
				  (file-name-directory (buffer-file-name))))
				")")
			 nil))
		  ,(format " - GNU Emacs %s" emacs-version)
		  ))
  (setq icon-title-format frame-title-format)

Buffers

  (setq confirm-nonexistent-file-or-buffer nil)
  (setq ibuffer-expert t)

Electric

  ;; Make return key also do indent of previous line
  (electric-indent-mode 1)
  (setq electric-pair-pairs '(
							  (?\( . ?\))
							  (?\[ . ?\])
							  ))
  (electric-pair-mode 1)

File Paths

Set file paths for built-in features like: auto-saves, backups, etc.

  (unless (file-directory-p dot-cache-dir)
	(make-directory dot-cache-dir t))

  ;; Set Directory locations
  (setq auto-save-list-file-prefix      (concat dot-cache-dir "/auto-save/"))
  (setq auto-save-file-name-transforms `((".*" ,auto-save-list-file-prefix t)))
  (setq backup-directory-alist         `((".*" . ,(concat dot-cache-dir "/backup/"))))
  (setq eshell-directory-name           (concat dot-cache-dir "/eshell/"))
  (setq package-user-dir                (concat dot-emacs-dir "/elpa"))
  (setq tramp-auto-save-directory       (concat dot-cache-dir "/tramp-auto-save/"))
  (setq tramp-backup-directory-alist    backup-directory-alist)
  (setq url-configuration-directory     (concat dot-cache-dir "/url/"))

  ;; Set file locations
  (setq bookmark-default-file           (concat dot-etc-dir "/bookmarks"))
  (setq nsm-settings-file               (concat dot-cache-dir "/network-security.data"))
  (setq tramp-persistency-file-name     (concat dot-cache-dir "/tramp"))

File Backups Versioning

Setup file backups versioning.

  (setq backup-by-copying t)    ; Don't cobbler symlinks
  (setq create-lockfiles nil)   ; Disable lockfiles (.#)
  (setq delete-old-versions t)  ; Cleanup backups
  (setq kept-new-versions 5)    ; Newest backups to keep
  (setq kept-old-versions 2)    ; Oldest backups to keep
  (setq version-control t)      ; Use version numbers on backups

Formatting

  ;; Columnn after line-wrapping happens
  (setq-default fill-column 80)

  ;; Automatically add newline on save at the end of the file
  (setq require-final-newline t)

  ;; End sentences with a single space
  (setq sentence-end-double-space nil)

  ;; `tabify' and `untabify' should only affect indentation
  (setq tabify-regexp "^\t* [ \t]+")

  ;; Do not wrap lines
  (setq-default truncate-lines t)

  ;; Wrap lines in the middle of words, gives a \ indicator
  (setq-default word-wrap nil)

Hide Elements

  (menu-bar-mode 0)
  (scroll-bar-mode 0)
  (tool-bar-mode 0)
  (tooltip-mode 0)
  (fringe-mode 0)
  (blink-cursor-mode 0)

  (setq inhibit-startup-message t)
  (setq initial-scratch-message nil)
  (setq ring-bell-function 'ignore)

Org

  (use-package org
	:custom
	(org-directory (concat (getenv "HOME") "/documents/org"))
	(org-ellipsis " ↴")
	(org-latex-toc-command "\\newpage \\tableofcontents \\newpage")
	(org-return-follows-link t)
	(org-src-fontify-natively t)
	(org-src-window-setup 'current-window)
	:config
	;; Do not open .org files in a split window
	(add-to-list 'org-link-frame-setup '(file . find-file))
	)

  ;; Enable syntax highlighting when exporting to .pdf
  ;; Load latex exporter
  (use-package ox-latex
	:ensure nil ; ox-latex.el is part of org
	:defer t
	:after org
	:custom
	;; Define how minted is added to source code blocks
	(org-latex-listings 'minted)
	(org-latex-minted-options '(("frame" "lines") ("linenos=true")))
	:config
	;; Add minted package to every LaTeX header
	(add-to-list 'org-latex-packages-alist '("" "minted"))
	;; Append -shell-escape so pdflatex exports minted correctly
	(add-to-list 'org-latex-pdf-process (replace-regexp-in-string
										 "%latex "
										 "%latex -shell-escape "
										 (car org-latex-pdf-process)))
	)

Recentf

  (use-package recentf
	:config
	(setq recentf-auto-cleanup 'never)
	(setq recentf-exclude '("~$" "/ssh:" "/sudo:"))
	(setq recentf-filename-handlers '(abbreviate-file-name))
	(setq recentf-max-menu-items 0)
	(setq recentf-max-saved-items 200)
	(setq recentf-save-file (concat dot-cache-dir "/recentf"))
	(recentf-mode)
	)

Tabs

  ;; Tabs
  (setq-default tab-width 4
				indent-tabs-mode t)

  ;; C/C++-like languages formatting style
  ;https://www.emacswiki.org/emacs/IndentingC
  (setq-default c-basic-offset 4
				sgml-basic-offset 4
				c-default-style "linux")

UTF-8

Set UTF-8 encoding as default.

  (prefer-coding-system 'utf-8-unix)
  (setq locale-coding-system 'utf-8-unix)
  ;; Default also sets file-name, keyboard and terminal coding system
  (set-default-coding-systems 'utf-8-unix)
  (set-buffer-file-coding-system 'utf-8-unix)
  (set-selection-coding-system 'utf-8-unix)

Window

  ;; Window rules
  (setq display-buffer-alist
		'(
		  ("^\\(\\*e?shell\\|vterm\\).*"
		   (display-buffer-in-side-window)
		   (window-height . 0.25)
		   (side . bottom)
		   (slot . -1))
		  ("\\*Faces\\*"
		   (display-buffer-in-side-window)
		   (window-height . 0.25)
		   (side . bottom)
		   (slot . 1))
		  ("\\*Help.*"
		   (display-buffer-in-side-window)
		   (window-height . 0.25)
		   (side . bottom)
		   (slot . 0))
		  ("\\*Occur\\*"
		   (display-buffer-in-side-window)
		   (window-height . 0.25)
		   (side . bottom)
		   (slot . 1))
		  ))

Functions

General Functions

Functions that only use built-in Emacs functionality.

  (defun display-startup-echo-area-message ()
	"Hide default startup message."
	(message nil))

  (defun dot/config-visit ()
	"Edit config file."
	(interactive)
	(find-file (concat dot-emacs-dir "/config.org")))

  (defun dot/config-reload ()
	"Reload config file."
	(interactive)
	(org-babel-load-file (concat dot-emacs-dir "/config.org")))

  (defun dot/find-file-emacsd ()
	"Find file under `dot-emacs-dir', recursively."
	(interactive)
	(let ((files (mapcar 'abbreviate-file-name
						 (directory-files-recursively dot-emacs-dir ""))))
	  (find-file (completing-read "Find file (emacs.d): " files nil t))))

  (defun dot/find-file-recentf ()
	"Use `completing-read' to open a recent file."
	(interactive)
	(let ((files (mapcar 'abbreviate-file-name recentf-list)))
	  (find-file (completing-read "Find file (recent): " files nil t))))

  (defun dot/indent-buffer ()
	"Indent each nonblank line in the buffer."
	(interactive)
	(save-excursion
	  (indent-region (point-min) (point-max) nil)))

  (defun dot/org-ret-at-point ()
	"Org return key at point.

  If point is on:
	link      -- follow it
	otherwise -- run the default (evil-ret) expression"
	(interactive)
	(let ((type (org-element-type (org-element-context))))
	  (pcase type
		('link (if org-return-follows-link (org-open-at-point) (evil-ret)))
		(_ (evil-ret))
		)))

  (defun dot/reload-theme ()
	"Reload custom theme."
	(interactive)
	(mapc 'load (file-expand-wildcards
				 (concat (car custom-theme-load-path) "*.el")))
	(load-theme load-theme t))

  (defun dot/sudo-find-file (filename)
	"Edit file FILENAME as root."
	(interactive "FOpen file (as root): ")
	(find-file (concat "/sudo:root@localhost:" filename)))

  (defun dot/sudo-this-file ()
	"Edit the current file as root."
	(interactive)
	(if buffer-file-name
		(find-alternate-file (concat "/sudo:root@localhost:" buffer-file-name))
	  (princ "Current buffer isn't a file")))

  (defun dot/M-x (command)
	"Prompt and execute COMMAND."
	(interactive "CCommand: ")
	(command-execute command))

  (defun split-follow-horizontally ()
	"Split and follow window."
	(interactive)
	(split-window-below)
	(other-window 1))
  (defun split-follow-vertically ()
	"Split and follow window."
	(interactive)
	(split-window-right)
	(other-window 1))

  (defun find-project-root ()
	"Return root of the project, determined by `.git/', `default-directory' otherwise."
	(let ((search-directory (locate-dominating-file "." ".git")))
	  (if search-directory
		  search-directory
		default-directory))
	)

  (defun find-file-in-project-root ()
	"Find file in project root."
	(interactive)
	(let ((default-directory (find-project-root)))
	  (call-interactively 'find-file)))


  ;; https://emacsredux.com/blog/2013/05/04/rename-file-and-buffer/
  (defun rename-file-and-buffer ()
	"Rename the current buffer and file it is visiting."
	(interactive)
	(let ((filename (buffer-file-name)))
	  (if (not (and filename (file-exists-p filename)))
		  (message "Buffer is not visiting a file!")
		(let ((new-name (read-file-name "New name: " filename)))
		  (cond
		   ((vc-backend filename) (vc-rename-file filename new-name))
		   (t
			(rename-file filename new-name t)
			(set-visited-file-name new-name t t)))))))

Functions that are only used for hook calls.

  (defun dot/hook-disable-line-numbers ()
	"Disable the line numbers."
	(display-line-numbers-mode 0))

  (defun dot/hook-disable-mode-line ()
	"Disable the mode line."
	(setq-local mode-line-format nil))

Package Functions

Functions that use package functionality.

Centaur Tabs Functions

  (with-eval-after-load 'centaur-tabs
	(defun centaur-tabs-buffer-groups ()
	  "Organize tabs into groups by buffer."
	  (list
	   (cond
		((string-equal "*" (substring (buffer-name) 0 1)) "Emacs")
		((memq major-mode '(org-mode
							emacs-lisp-mode)) "Org Mode")
		((derived-mode-p 'dired-mode) "Dired")
		((derived-mode-p 'prog-mode
						 'text-mode) "Editing")
		(t "User"))))

	(defun centaur-tabs-hide-tab (buffer)
	  "Hide from the tab bar by BUFFER name."
	  (let ((name (format "%s" buffer)))
		(or
		 ;; Current window is dedicated window
		 (window-dedicated-p (selected-window))

		 ;; Buffer name does match below blacklist
		 (string-match-p
		  (concat "^\\*\\("
				  "e?shell\\|"
				  "Compile-Log\\|"
				  "Completions\\|"
				  "clangd\\|"       ; lsp c/c++
				  "Faces\\|"
				  "Flycheck\\|"
				  "Help\\|"
				  "helpful\\|"
				  "httpd\\|"
				  "iph\\|"          ; lsp php
				  "Occur\\|"
				  "org-roam"
				  "\\).*")
		  name)
		 )))

	(defun dot/centaur-tabs-buffer-cleanup ()
	  "Clean up all the hidden buffers."
	  (interactive)
	  (dolist (buffer (buffer-list))
		(when (centaur-tabs-hide-tab buffer)
		  (kill-buffer buffer))
		)
	  )

	(defun dot/centaur-tabs-kill-buffer-or-window ()
	  "Delete window of the current buffer, also kill if the buffer is hidden."
	  (interactive)
	  (if (centaur-tabs-hide-tab (buffer-name))
		  (kill-buffer-and-window)
		(delete-window))
	  )
	)

Dashboard Functions

  (with-eval-after-load 'dashboard
	(defun dot/dashboard-goto ()
	  "Go to the *dashboard* buffer, create if non-existing."
	  (interactive)
	  (let ((buffer "*dashboard*"))
		(unless (get-buffer buffer)
		  (generate-new-buffer buffer)
		  (dashboard-refresh-buffer))
		(switch-to-buffer buffer)))
	)

Fix keybinds..

  (defun dot/dashboard-goto-bookmarks ()
	"Move point to bookmarks."
	(interactive)
	(funcall (local-key-binding "m")))

  (defun dot/dashboard-goto-projects ()
	"Move point to projects."
	(interactive)
	(funcall (local-key-binding "p")))

  (defun dot/dashboard-goto-recent-files ()
	"Move point to recent files."
	(interactive)
	(funcall (local-key-binding "r")))

LSP Functions

  (defun lsp-format-region-or-buffer ()
	"Format the selection (or buffer) with LSP."
	(interactive)
	(unless (bound-and-true-p lsp-mode)
	  (user-error "Not in an LSP buffer"))
	(call-interactively
	 (if (use-region-p)
		 #'lsp-format-region
	   #'lsp-format-buffer)))

Neotree Functions


  (defun neotree-toggle-in-project-root ()
	"Toggle Neotree in project root."
	(interactive)
	(let ((default-directory (find-project-root)))
	  (call-interactively #'neotree-toggle)))

Which-Key Functions

  (with-eval-after-load 'which-key
	(defun dot/which-key-prefix-then-key-order-alpha (acons bcons)
	  "Order y prefix, then lexicographical."
	  (let ((apref? (which-key--group-p (cdr acons)))
			(bpref? (which-key--group-p (cdr bcons))))
		(if (not (eq apref? bpref?))
			(and (not apref?) bpref?)
		  (which-key-key-order-alpha acons bcons))))
	)

Advice and Aliases

Advice

Define default terminal option.

  (defun dot/ansi-term (program &optional new-buffer-name)
	(interactive (list dot/shell)))
  (advice-add 'ansi-term :before #'dot/ansi-term)

Aliases

General

Make confirm easier, by just pressing y/n.

  (defalias 'yes-or-no-p 'y-or-n-p)

Package

Evil command aliases.

  (with-eval-after-load 'evil-ex
    (evil-ex-define-cmd "W" "w")
    (evil-ex-define-cmd "Q" "q")
    (evil-ex-define-cmd "WQ" "wq")
    (evil-ex-define-cmd "Wq" "wq"))

Hooks

  ;; Delete trailing whitespace
  (add-hook 'before-save-hook 'delete-trailing-whitespace)

  ;; Highlight parenthesis
  (add-hook 'prog-mode-hook 'show-paren-mode)

  ;; Enable 'table of contents' in org
  (add-hook 'org-mode-hook 'toc-org-mode)

  ;; C++ // style comments in c-mode
  (add-hook 'c-mode-hook (lambda () (c-toggle-comment-style 0)))

  ;; LaTeX, set correct tab mode
  (add-hook 'latex-mode-hook (lambda () (setq indent-tabs-mode t)))

  ;; Disable line numbers in terminal mode (breaks output otherwise)
  (add-hook 'term-mode-hook 'dot/hook-disable-line-numbers)

  ;; Wrap lines in the middle of words, gives a \ indicator
  (add-hook 'visual-line-mode-hook (lambda () (setq word-wrap nil)))

Key Bindings

Useful links:
Mastering Emacs key bindings
use-package bind key
GNU remapping commands
GNU binding combinations of modifiers
Doom Emacs bindings

Disable Default

Disable keybinds of default modes that clash with the custom keybinds below.

  (with-eval-after-load 'org
	(define-key org-mode-map (kbd "M-h") nil)
	(define-key org-mode-map (kbd "C-M-h") nil))

  (with-eval-after-load 'cc-mode
	(define-key c-mode-base-map (kbd "M-j") nil)
	(define-key c-mode-base-map (kbd "C-M-h") nil))

Disable Package

Disable keybinds of installed packages that clash with the custom keybinds below.

  (with-eval-after-load 'evil-states
	(define-key evil-motion-state-map (kbd dot/leader-key) nil))

  (with-eval-after-load 'php-mode
	(define-key php-mode-map (kbd "M-j") nil)
	(define-key php-mode-map (kbd "C-M-h") nil))

Set Default

Set custom keybinds to functionality of default modes.

  ;; Buffers
  (global-set-key (kbd "C-x C-b") 'ibuffer)
  (global-set-key (kbd "M-w") 'kill-buffer-and-window)

  ;; Config edit/reload
  (global-set-key (kbd "C-c r") 'config-reload)
  (global-set-key (kbd "C-c v") 'config-visit)

  ;; Find file
  (global-set-key (kbd "C-x C-f") 'find-file-in-project-root)

  ;; Split and follow window
  (global-set-key (kbd "C-x 2") 'split-follow-horizontally)
  (global-set-key (kbd "C-x 3") 'split-follow-vertically)

  ;; Terminal
  (global-set-key (kbd "<s-backspace>") 'ansi-term)

Set Package

Set custom keybinds to functionality of custom packages.

  ;; Buffers
  (global-set-key (kbd "M-h") 'centaur-tabs-backward-tab)
  (global-set-key (kbd "M-j") 'centaur-tabs-forward-group)
  (global-set-key (kbd "M-k") 'centaur-tabs-backward-group)
  (global-set-key (kbd "M-l") 'centaur-tabs-forward-tab)
  (global-set-key (kbd "C-M-h") 'centaur-tabs-move-current-tab-to-left)
  (global-set-key (kbd "C-M-l") 'centaur-tabs-move-current-tab-to-right)
  (global-set-key (kbd "M-\`") 'evil-switch-to-windows-last-buffer)

  (global-set-key (kbd "M-s") 'avy-goto-char-timer)
  (global-set-key (kbd "M-x") 'dot/M-x)

  ;; Helpful overwrite default help functions
  (global-set-key [remap describe-command]  #'helpful-command)
  (global-set-key [remap describe-function] #'helpful-callable)
  (global-set-key [remap describe-key]      #'helpful-key)
  (global-set-key [remap describe-symbol]   #'helpful-at-point)
  (global-set-key [remap describe-variable] #'helpful-variable)
  (which-key-add-key-based-replacements "C-h o" "describe-symbol-at-point")

  ;; Company completion selection
  (with-eval-after-load 'company
	(define-key company-active-map (kbd "M-n") nil)
	(define-key company-active-map (kbd "M-p") nil)
	(define-key company-active-map (kbd "M-h") #'company-abort)
	(define-key company-active-map (kbd "M-j") #'company-select-next)
	(define-key company-active-map (kbd "M-k") #'company-select-previous)
	(define-key company-active-map (kbd "M-l") #'company-complete-selection)
	(define-key company-active-map (kbd "<escape>") #'company-abort))
  ; https://github.com/company-mode/company-mode/blob/master/company.el#L661

  ;; Evil command history selection
  (with-eval-after-load 'evil-ex
	(define-key evil-ex-completion-map (kbd "M-h") 'abort-recursive-edit)
	(define-key evil-ex-completion-map (kbd "M-j") #'next-complete-history-element)
	(define-key evil-ex-completion-map (kbd "M-k") #'previous-complete-history-element)
	(define-key evil-ex-completion-map (kbd "M-l") 'exit-minibuffer))

  ;; Minibuffer completion selection
  (general-def minibuffer-local-map
	"M-h" #'abort-recursive-edit
	"M-j" #'selectrum-next-candidate
	"M-k" #'selectrum-previous-candidate
	"M-l" #'selectrum-select-current-candidate)

  ; Overwrite evil keymaps
  ;(evil-global-set-key 'motion (kbd "C-w") 'kill-this-buffer)
  ;(evil-define-key 'motion 'global (kbd "C-w") 'kill-this-buffer)
  ;(define-key evil-motion-state-map (kbd "C-w") 'kill-this-buffer) ; @Todo test this with nil
  ;https://github.com/noctuid/evil-guide#global-keybindings-and-evil-states

  (with-eval-after-load 'evil-states
	;; Global evil keymap
	(general-def evil-normal-state-map
	 "C-n" 'neotree-toggle-in-project-root)

	;; Dashboard
	(general-def 'normal dashboard-mode-map
	 [down-mouse-1] 'widget-button-click
	 "g" #'dashboard-refresh-buffer
	 "m" #'dot/dashboard-goto-bookmarks
	 "p" #'dot/dashboard-goto-projects
	 "r" #'dot/dashboard-goto-recent-files
	 )

	;; Elfeed
	(general-def 'normal elfeed-search-mode-map
	 "b"  'elfeed-search-browse-url
	 "c"  'elfeed-search-clear-filter
	 "gr" '(elfeed-search-update--force  :which-key "Refresh buffer")
	 "gR" '(elfeed-search-fetch          :which-key "Update feeds")
	 "q"  'elfeed-search-quit-window
	 "u"  'elfeed-search-tag-all-unread
	 "U"  nil
	 "r"  'elfeed-search-untag-all-unread
	 )

	(general-def 'normal elfeed-show-mode-map
	 "b" #'elfeed-show-visit
	 "g" #'elfeed-show-refresh
	 "q" #'elfeed-kill-buffer
	 "u" #'elfeed-show-tag--unread
	 "y" #'elfeed-show-yank
	 )

	;; Minibuffer
	(general-def 'normal minibuffer-local-map
	  "<up>"   #'selectrum-previous-candidate
	  "<down>" #'selectrum-next-candidate
	  "j"      #'selectrum-next-candidate
	  "k"      #'selectrum-previous-candidate
	  )

	 ;; Neotree
	(general-def 'normal neotree-mode-map
	 "RET"       'neotree-enter
	 "<backtab>" 'neotree-collapse-all ; <S-tab>
	 "c"         'neotree-create-node
	 "r"         'neotree-rename-node
	 "d"         'neotree-delete-node
	 "h"         'neotree-select-previous-sibling-node
	 "j"         'neotree-next-line
	 "k"         'neotree-previous-line
	 "l"         'neotree-enter
	 "R"         'neotree-refresh
	 "C"         'neotree-change-root
	 "H"         'neotree-hidden-file-toggle
	 "q"         'neotree-hide
	 )

	;; Org
	(general-def 'normal org-mode-map
	 "RET" 'dot/org-ret-at-point)
	(general-def 'insert org-mode-map
	  "RET" 'evil-ret)
	)

Leader

General.el ~leader key binds.

Global Leader

  (general-create-definer space-leader
	:prefix dot/leader-key
	:non-normal-prefix dot/leader-alt-key
	:global-prefix dot/leader-alt-key
	:states '(normal visual insert motion emacs))

  (space-leader
	"SPC"       '(dot/M-x                    :which-key "Execute command")
	"RET"       '(bookmark-jump              :which-key "Jump to bookmark")

	;; Buffer / bookmark
	"b"         '(:ignore t                         :which-key "buffer/bookmark")
	"b a"       '(auto-revert-mode                  :which-key "Auto revert buffer")
	"b b"       '(switch-to-buffer                  :which-key "Switch buffer")
	"b d"       '(dot/dashboard-goto                :which-key "Dashboard")
	"b k"       '(kill-current-buffer               :which-key "Kill buffer")
	"b m"       '(bookmark-set                      :which-key "Make bookmark")
	"b n"       '(evil-buffer-new                   :which-key "New empty buffer")
	"b r"       '(revert-buffer                     :which-key "Revert buffer")
	"b s"       '(basic-save-buffer                 :which-key "Save buffer")
	"b B"       '(ibuffer                           :which-key "List buffers")
	"b C"       '(dot/centaur-tabs-buffer-cleanup   :which-key "Cleanup buffers")
	"b M"       '(bookmark-delete                   :which-key "Delete bookmark")
	"b S"       '(evil-write-all                    :which-key "Save all buffers")
	"b <left>"  '(previous-buffer                   :which-key "Previous buffer")
	"b <right>" '(next-buffer                       :which-key "Next buffer")

	;; Comments
	"c"   '(:ignore t                               :which-key "comment/config")
	"c c" '(evilnc-comment-or-uncomment-lines       :which-key "Toggle comment")
	"c p" '(evilnc-comment-or-uncomment-paragraphs  :which-key "Toggle comment paragraph")
	"c y" '(evilnc-comment-and-kill-ring-save       :which-key "Comment and copy")

	;; Elisp
	"e"   '(:ignore t                        :which-key "elisp")
	"e b" '(eval-buffer                      :which-key "Evaluate buffer")
	"e e" '(eval-last-sexp                   :which-key "Evaluate last sexp")
	"e r" '(eval-region                      :which-key "Evaluate region")
	"e t" '(dot/reload-theme                 :which-key "Reload theme")

	;; File
	"f"     '(:ignore t                      :which-key "file")
	"f e"   '(:ignore t                      :which-key "emacs")
	"f e c" '(dot/config-visit               :which-key "Config visit")
	"f e f" '(dot/find-file-emacsd           :which-key "Find emacs.d file")
	"f e r" '(dot/config-reload              :which-key "Config reload")
	"f d"   '(dired                          :which-key "Find directory")
	"f f"   '(find-file-in-project-root      :which-key "Find file")
	"f r"   '(dot/find-file-recentf          :which-key "Find recent file ")
	"f R"   '(rename-file-and-buffer         :which-key "Rename file")
	"f s"   '(basic-save-buffer              :which-key "Save file")
	"f S"   '(write-file                     :which-key "Save file as...")
	"f u"   '(dot/sudo-find-file             :which-key "Sudo find file")
	"f U"   '(dot/sudo-this-file             :which-key "Sudo this file")

	;; Help
	"h"   '(:keymap help-map                 :which-key "help")
	"h o" '(:ignore t                        :which-key "describe-symbol-at-point")

	;; Insert
	"i"   '(:ignore t                        :which-key "insert")
	"i b" '(dot/indent-buffer                :which-key "Indent buffer")
	"i r" '(indent-region                    :which-key "Indent region")
	"i s" '(yas-insert-snippet               :which-key "Insert snippet")

	;; Notes
	"n"     '(:ignore t                      :which-key "notes")
	"n r"   '(:ignore t                      :which-key "roam")
	"n r b" '(org-roam-switch-to-buffer      :which-key "Switch to buffer")
	"n r i" '(org-roam-insert                :which-key "Insert")
	"n r c" '(org-roam-capture               :which-key "Org Roam Capture")
	"n r f" '(org-roam-find-file             :which-key "Find file")
	"n r g" '(org-roam-graph-show            :which-key "Show graph")
	"n r r" '(org-roam                       :which-key "Org Roam")
	"n r s" '(org-roam-server-mode           :which-key "Org Roam Server")
	"n r C" '(org-roam-build-cache           :which-key "Build cache")
	"n r I" '(org-roam-insert-immediate      :which-key "Insert without org-capture")

	;; Projectile
	"p"   '(:keymap projectile-command-map :package projectile :which-key "projectile")

	;; Quit
	"q"   '(:ignore t                        :which-key "quit")
	"q q" '(save-buffers-kill-terminal       :which-key "Quit Emacs")
	"q Q" '(save-buffers-kill-emacs          :which-key "Quit Emacs (and daemon)")
	"q f" '(delete-frame                     :which-key "Close frame")
	"q o" '(delete-other-frames              :which-key "Close other frames")

	;; Search
	"s"   '(:ignore t                        :which-key "search")
	"s a" '(avy-goto-char-timer              :which-key "Avy goto char")
	"s b" '(bookmark-jump                    :which-key "Jump to bookmark")

	;; Tabs / toggle
	"t"   '(:ignore t                                 :which-key "tabs/toggle")
	"t b" '(centaur-tabs-group-buffer-groups          :which-key "Group tabs by buffer")
	"t p" '(centaur-tabs-group-by-projectile-project  :which-key "Group tabs by project")
	"t h" '(centaur-tabs-backward-group               :which-key "Tab backward group")
	"t j" '(centaur-tabs-select-end-tab               :which-key "Tab select first")
	"t k" '(centaur-tabs-select-beg-tab               :which-key "Tab select last")
	"t l" '(centaur-tabs-forward-group                :which-key "Tab forward group")
	"t n" '(neotree-toggle-in-project-root            :which-key "Toggle Neotree")
	"t w" '(visual-line-mode                          :which-key "Toggle line wrapping")

	;; Update packages
	"u"   '(auto-package-update-now          :which-key "Update packages")

	;; Window
	"w"         '(:ignore t                               :which-key "window")
	"w +"       '(evil-window-increase-height             :which-key "Increase window height")
	"w -"       '(evil-window-decrease-height             :which-key "Decrease window height")
	"w <"       '(evil-window-decrease-width              :which-key "Decrease window width")
	"w ="       '(balance-windows                         :which-key "Balance windows")
	"w >"       '(evil-window-increase-width              :which-key "Increase window width")
	"w _"       '(evil-window-set-height                  :which-key "Maximize window height")
	"w h"       '(windmove-left                           :which-key "Focus window left")
	"w j"       '(windmove-down                           :which-key "Focus window down")
	"w k"       '(windmove-up                             :which-key "Focus window up")
	"w l"       '(windmove-right                          :which-key "Focus window right")
	"w o"       '(delete-other-windows                    :which-key "Close other windows")
	"w s"       '(split-follow-horizontally               :which-key "Split horizontal")
	"w v"       '(split-follow-vertically                 :which-key "Split vertical")
	"w w"       '(other-window                            :which-key "Focus other window")
	"w q"       '(dot/centaur-tabs-kill-buffer-or-window  :which-key "Close window")
	"w <left>"  '(windmove-left                           :which-key "Focus window left")
	"w <right>" '(windmove-right                          :which-key "Focus window right")
	"w <up>"    '(windmove-up                             :which-key "Focus window up")
	"w <down>"  '(windmove-down                           :which-key "Focus window down")
	;; winner-redo (built-in window history)
	;; winner-undo
	)

Evaluated keybinds.

  (with-eval-after-load 'lsp-mode
	(space-leader lsp-mode-map
	  "l" lsp-command-map
	  )
	)

Source: https://github.com/redguardtoo/emacs.d/blob/master/lisp/init-evil.el#L712 https://github.com/suyashbire1/emacs.d/blob/master/init.el

Local Leader

  (general-create-definer local-leader
	:prefix dot/localleader-key
	:non-normal-prefix dot/localleader-alt-key
	:global-prefix dot/localleader-alt-key
	:states '(normal visual insert motion emacs)

	""    '(:ignore t                        :which-key "<localleader>")
	)

  (local-leader org-mode-map
	"'"   '(org-edit-special                 :which-key "Org edit")
	"c"   '(org-edit-special                 :which-key "Org edit")
	"e"   '(org-export-dispatch              :which-key "Org export")
	"l"   '(org-insert-link                  :which-key "Org make link")
	"o"   '(org-open-at-point                :which-key "Org open at point")

	"i"         '(:ignore t                  :which-key "insert")
	"i h"       '(org-insert-heading         :which-key "Org insert heading")

	"s"         '(:ignore t                  :which-key "tree/subtree")
	"s h"       '(org-promote-subtree        :which-key "Org promote subtree")
	"s j"       '(org-move-subree-down       :which-key "Org move subtree down")
	"s k"       '(org-move-subtree-up        :which-key "Org move subtree up")
	"s l"       '(org-demote-subtree         :which-key "Org demote subtree")
	"s <left>"  '(org-promote-subtree        :which-key "Org promote subtree")
	"s <right>" '(org-demote-subtree         :which-key "Org demote subtree")
	"s <up>"    '(org-move-subree-up         :which-key "Org move subtree up")
	"s <down>"  '(org-move-subtree-down      :which-key "Org move subtree down")
	)

  (local-leader org-src-mode-map
	"'"   '(org-edit-src-exit                :which-key "Org exit edit")
	"c"   '(org-edit-src-exit                :which-key "Org exit edit")
	"k"   '(org-edit-src-abort               :which-key "Org abort edit")
	)

  (define-key org-src-mode-map (kbd "C-c C-c") #'org-edit-src-exit)

  (local-leader elfeed-search-mode-map
	"g"   '(elfeed-search-update--force      :which-key "Elfeed refresh buffer")
	"G"   '(elfeed-search-fetch              :which-key "Elfeed update feeds")
	)

  (local-leader elfeed-show-mode-map
	"g"   '(elfeed-show-refresh               :which-key "Elfeed refresh buffer")
	)

  ;; c-fill-paragraph Reflow comment
  ;; https://youtu.be/hbmV1bnQ-i0?t=1910

Notes

Org mode keybinds:

Keystroke Description Function
<C-c C-c> Update tags/headline (org-ctrl-c-ctrl-c)
<C-return> Insert heading (org-insert-heading-respect-content)
<C-x n s> ? (org-narrow-to-subtree)
<C-x n w> ? (widen)
<M-return> Insert heading (org-meta-return)
<M-S-return> Insert todo heading (org-insert-todo-heading)
<M-down> Move subtree down (org-metadown)
<M-left> Promote heading (org-metaleft)
<M-right> Demote heading (org-metaright)
<M-up> Move subtree up (org-metaup)
<S-left/right> Cycle to next todo keyword (org-shiftleft/org-shiftright)
<S-up/down> Cycle todo priority (org-shiftup/org-shiftdown)