- Introduction
- Important to load first
- Appearance
- Development
- Multi File Example
- Other Packages
- Runtime Performance
;; Kickstart.emacs is *not* a distribution.
;; It's a template for your own configuration.
;; It is *recommeded* to configure it from the *config.org* file.
;; The goal is that you read every line, top-to-bottom, understand
;; what your configuration is doing, and modify it to suit your needs.
;; You can delete this when you're done. It's your config now. :)
Make startup faster by reducing the frequency of garbage collection. This will be set back when startup finishes.
;; The default is 800 kilobytes. Measured in bytes.
(setq gc-cons-threshold (* 50 1000 1000))
Auto-Tangle Org configuration file for better startup times. If you want to use this don’t forget to add this to the top of the org document (#+PROPERTY: header-args:emacs-lisp :tangle ./init.el :mkdirp yes)
Remember, if this code can’t be loaded (errors before this code), the init.el file won’t update on change! To fix this, you need to find this file (C-x C-f), fix the error and press C-c C-v t to tangle it manually.
This snippet adds a hook to org-mode buffers so that start/org-babel-tangle-config gets executed each time such a buffer gets saved. This function checks to see if the file being saved is the Emacs.org file you’re looking at right now, and if so, automatically exports the configuration here to the associated output files.
(defun start/org-babel-tangle-config ()
"Automatically tangle our Emacs.org config file when we save it. Credit to Emacs From Scratch for this one!"
(when (string-equal (file-name-directory (buffer-file-name))
(expand-file-name user-emacs-directory))
;; Dynamic scoping to the rescue
(let ((org-confirm-babel-evaluate nil))
(org-babel-tangle))))
(add-hook 'org-mode-hook (lambda () (add-hook 'after-save-hook #'start/org-babel-tangle-config)))
We use the default package manager package.el with use-package. Alternative package managers (straight.el, elpaca, etc.) are useful if you want to install packages from git repositories, if you want a specific, not very popular package that is not available on elpa or melpa, or you want UI (elpaca) and other things.
If you are interested in these other package managers, check out their git repositories or search for more package managers. In my experience Package.el is not slow and gets the job done.
To update/upgrade packages, use the package-upgrade-all command. Check out the use-package documentation to see how to use it. With Emacs 29 use-package is now built-in.
(require 'use-package-ensure) ;; Load use-package-always-ensure
(setq use-package-always-ensure t) ;; Always ensures that a package is installed
(setq package-archives '(("melpa" . "https://melpa.org/packages/") ;; Sets default package repositories
("org" . "https://orgmode.org/elpa/")
("elpa" . "https://elpa.gnu.org/packages/")
("nongnu" . "https://elpa.nongnu.org/nongnu/"))) ;; For Eat Terminal
An extensible vi/vim layer for Emacs. Because…let’s face it. The Vim keybindings are just plain better. Notes:
- You can toggle evil mode with C-z.
- To paste without copy (yank) select the text and use P (shift-p).
If you don’t want to use evil-mode don’t forget to remove:
- Messages buffer fix in Good default section (:ghook)
- And also change general.el keybindings and setup (general-evil-setup, :states, etc.)
(use-package evil
:init ;; Execute code Before a package is loaded
(evil-mode)
:config ;; Execute code After a package is loaded
(evil-set-initial-state 'eat-mode 'insert) ;; Set initial state in eat terminal to insert mode
:custom ;; Customization of package custom variables
(evil-want-keybinding nil) ;; Disable evil bindings in other modes (It's not consistent and not good)
(evil-want-C-u-scroll t) ;; Set C-u to scroll up
(evil-want-C-i-jump nil) ;; Disables C-i jump
(evil-undo-system 'undo-redo) ;; C-r to redo
(org-return-follows-link t) ;; Sets RETURN key in org-mode to follow links
;; Unmap keys in 'evil-maps. If not done, org-return-follows-link will not work
:bind (:map evil-motion-state-map
("SPC" . nil)
("RET" . nil)
("TAB" . nil)))
(use-package evil-collection
:after evil
:config
;; Setting where to use evil-collection
(setq evil-collection-mode-list '(dired ibuffer magit corfu vertico consult))
(evil-collection-init))
A keybinding framework to set keybindings easily. The Leader key is what you will press when you want to access your keybindings (SPC + . Find file). To search and replace, use query-replace-regexp to replace one by one C-M-% (SPC to replace n to skip).
(use-package general
:config
(general-evil-setup)
;; Set up 'SPC' as the leader key
(general-create-definer start/leader-keys
:states '(normal insert visual motion emacs)
:keymaps 'override
:prefix "SPC" ;; Set leader key
:global-prefix "C-SPC") ;; Set global leader key
(start/leader-keys
"." '(find-file :wk "Find file")
"TAB" '(comment-line :wk "Comment lines")
"p" '(projectile-command-map :wk "Projectile command map"))
(start/leader-keys
"f" '(:ignore t :wk "Find")
"f c" '((lambda () (interactive) (find-file "~/.config/emacs/config.org")) :wk "Edit emacs config")
"f r" '(consult-recent-file :wk "Recent files")
"f f" '(consult-fd :wk "Fd search for files")
"f g" '(consult-ripgrep :wk "Ripgrep search in files")
"f l" '(consult-line :wk "Find line")
"f i" '(consult-imenu :wk "Imenu buffer locations"))
(start/leader-keys
"b" '(:ignore t :wk "Buffer Bookmarks")
"b b" '(consult-buffer :wk "Switch buffer")
"b k" '(kill-this-buffer :wk "Kill this buffer")
"b i" '(ibuffer :wk "Ibuffer")
"b n" '(next-buffer :wk "Next buffer")
"b p" '(previous-buffer :wk "Previous buffer")
"b r" '(revert-buffer :wk "Reload buffer")
"b j" '(consult-bookmark :wk "Bookmark jump"))
(start/leader-keys
"d" '(:ignore t :wk "Dired")
"d v" '(dired :wk "Open dired")
"d j" '(dired-jump :wk "Dired jump to current"))
(start/leader-keys
"e" '(:ignore t :wk "Eglot Evaluate")
"e e" '(eglot-reconnect :wk "Eglot Reconnect")
"e f" '(eglot-format :wk "Eglot Format")
"e l" '(consult-flymake :wk "Consult Flymake")
"e b" '(eval-buffer :wk "Evaluate elisp in buffer")
"e r" '(eval-region :wk "Evaluate elisp in region"))
(start/leader-keys
"g" '(:ignore t :wk "Git")
"g g" '(magit-status :wk "Magit status"))
(start/leader-keys
"h" '(:ignore t :wk "Help") ;; To get more help use C-h commands (describe variable, function, etc.)
"h q" '(save-buffers-kill-emacs :wk "Quit Emacs and Daemon")
"h r" '((lambda () (interactive)
(load-file "~/.config/emacs/init.el"))
:wk "Reload Emacs config"))
(start/leader-keys
"s" '(:ignore t :wk "Show")
"s e" '(eat :wk "Eat terminal"))
(start/leader-keys
"t" '(:ignore t :wk "Toggle")
"t t" '(visual-line-mode :wk "Toggle truncated lines (wrap)")
"t l" '(display-line-numbers-mode :wk "Toggle line numbers")))
(use-package emacs
:custom
(menu-bar-mode nil) ;; Disable the menu bar
(scroll-bar-mode nil) ;; Disable the scroll bar
(tool-bar-mode nil) ;; Disable the tool bar
;;(inhibit-startup-screen t) ;; Disable welcome screen
(delete-selection-mode t) ;; Select text and delete it by typing.
(electric-indent-mode nil) ;; Turn off the weird indenting that Emacs does by default.
(electric-pair-mode t) ;; Turns on automatic parens pairing
(blink-cursor-mode nil) ;; Don't blink cursor
(global-auto-revert-mode t) ;; Automatically reload file and show changes if the file has changed
;;(dired-kill-when-opening-new-dired-buffer t) ;; Dired don't create new buffer
;;(recentf-mode t) ;; Enable recent file mode
;;(global-visual-line-mode t) ;; Enable truncated lines
;;(display-line-numbers-type 'relative) ;; Relative line numbers
(global-display-line-numbers-mode t) ;; Display line numbers
(mouse-wheel-progressive-speed nil) ;; Disable progressive speed when scrolling
(scroll-conservatively 10) ;; Smooth scrolling
;;(scroll-margin 8)
(tab-width 4)
(make-backup-files nil) ;; Stop creating ~ backup files
(auto-save-default nil) ;; Stop creating # auto save files
:hook
(prog-mode . (lambda () (hs-minor-mode t))) ;; Enable folding hide/show globally
:config
;; Move customization variables to a separate file and load it, avoid filling up init.el with unnecessary variables
(setq custom-file (locate-user-emacs-file "custom-vars.el"))
(load custom-file 'noerror 'nomessage)
:bind (
([escape] . keyboard-escape-quit) ;; Makes Escape quit prompts (Minibuffer Escape)
)
;; Fix general.el leader key not working instantly in messages buffer with evil mode
:ghook ('after-init-hook
(lambda (&rest _)
(when-let ((messages-buffer (get-buffer "*Messages*")))
(with-current-buffer messages-buffer
(evil-normalize-keymaps))))
nil nil t)
)
Set gruvbox theme, if you want some themes try out doom-themes. Use consult-theme to easily try out themes (Epilepsy Warning).
(use-package gruvbox-theme
:config
(load-theme 'gruvbox-dark-medium t)) ;; We need to add t to trust this package
With Emacs version 29, true transparency has been added.
(add-to-list 'default-frame-alist '(alpha-background . 90)) ;; For all new frames henceforth
(set-face-attribute 'default nil
;; :font "JetBrainsMono NF" ;; Set your favorite type of font or download JetBrains Mono
:height 120
:weight 'medium)
;; This sets the default font on all graphical frames created after restarting Emacs.
;; Does the same thing as 'set-face-attribute default' above, but emacsclient fonts
;; are not right unless I also add this method of setting the default font.
;; (add-to-list 'default-frame-alist '(font . "JetBrainsMono NF")) ;; Set your favorite font
(setq-default line-spacing 0.12)
You can use the bindings C-+ C– for zooming in/out. You can also use CTRL plus the mouse wheel for zooming in/out.
(use-package emacs
:bind
("C-+" . text-scale-increase)
("C--" . text-scale-decrease)
("<C-wheel-up>" . text-scale-increase)
("<C-wheel-down>" . text-scale-decrease))
Replace the default modeline with a prettier more useful.
(use-package doom-modeline
:init (doom-modeline-mode 1)
:custom
(doom-modeline-height 25) ;; Sets modeline height
(doom-modeline-bar-width 5) ;; Sets right bar width
(doom-modeline-persp-name t) ;; Adds perspective name to modeline
(doom-modeline-persp-icon t)) ;; Adds folder icon next to persp name
Project interaction library for Emacs.
(use-package projectile
:init
(projectile-mode)
:custom
(projectile-run-use-comint-mode t) ;; Interactive run dialog when running projects inside emacs (like giving input)
(projectile-switch-project-action #'projectile-dired) ;; Open dired when switching to a project
(projectile-project-search-path '("~/projects/" "~/work/" ("~/github" . 1)))) ;; . 1 means only search the first subdirectory level for projects
;; Use Bookmarks for smaller, not standard projects
Language Server Protocol Support for Emacs. The built-in is now Eglot (with emacs 29).
Eglot is fast and minimal, but requires manual setup for LSP servers (downloading). For more information how to use. One alternative to Eglot is Lsp-mode, check out the project wiki page for more information.
Eglot is easy to set up, but the only difficult part is downloading and setting up the lsp servers. After that just add a hook with eglot-ensure to automatically start eglot for a given file type. And you are done.
As an example to use C, C++ you need to install clangd(or ccls) and uncomment the following lines. Now the language server will start automatically when opening any c,c++ file.
A harder example is Lua. Download the lua-language-server from their git repository, make the lua-language-server file executable at lua-language-server/bin. Uncomment the following lines and change the path to the language server executable. Now the language server will work. Or add the lua-language-server executable to your path.
If you can use a package manager just install the lsp server and add a hook. Use visual block to uncomment easily in Org documents (C-v).
;;(use-package eglot
;; :ensure nil ;; Don't install eglot because it's now built-in
;; :hook ((c-mode c++-mode ;; Autostart lsp servers for a given mode
;; lua-mode) ;; Lua-mode needs to be installed
;; . eglot-ensure)
;; :custom
;; ;; Good default
;; (eglot-events-buffer-size 0) ;; No event buffers (Lsp server logs)
;; (eglot-autoshutdown t);; Shutdown unused servers.
;; (eglot-report-progress nil) ;; Disable lsp server logs (Don't show lsp messages at the bottom, java)
;; ;; Manual lsp servers
;; :config
;; (add-to-list 'eglot-server-programs
;; `(lua-mode . ("PATH_TO_THE_LSP_FOLDER/bin/lua-language-server" "-lsp"))) ;; Adds our lua lsp server to eglot's server list
;; )
A template system for Emacs. And yasnippet-snippets is a snippet collection package. To use it write out the full keyword (or use autocompletion) and press Tab.
(use-package yasnippet-snippets
:hook (prog-mode . yas-minor-mode))
It’s not required for every language like C,C++,C#,Java,Javascript etc. to install language mode packages, but for more specific languages it is necessary for syntax highlighting. If you want to use TreeSitter, check out this website or try out Treesit-auto. Currently it’s tedious to use Treesitter, because emacs has not yet fully migrated to it.
Example, how to setup a language mode (if you don’t want it, feel free to delete it). Use SPC-tab to uncomment the lines.
Org mode is one of the things that emacs is loved for. Once you’ve used it for a bit, you’ll understand why people love it. Even reading about it can be inspiring! For example, this document is effectively the source code and descriptions bound into the one document, much like the literate programming ideas that Donald Knuth made famous.
(use-package org
:ensure nil
:custom
(org-edit-src-content-indentation 4) ;; Set src block automatic indent to 4 instead of 2.
:hook
(org-mode . org-indent-mode) ;; Indent text
;; The following prevents <> from auto-pairing when electric-pair-mode is on.
;; Otherwise, org-tempo is broken when you try to <s TAB...
;;(org-mode . (lambda ()
;; (setq-local electric-pair-inhibit-predicate
;; `(lambda (c)
;; (if (char-equal c ?<) t (,electric-pair-inhibit-predicate c))))))
)
(use-package toc-org
:commands toc-org-enable
:hook (org-mode . toc-org-mode))
Prettify headings and plain lists in Org mode. Modern version of org-bullets.
(use-package org-superstar
:after org
:hook (org-mode . org-superstar-mode))
Org-tempo is not a separate package but a module within org that can be enabled. Org-tempo allows for ‘<s’ followed by TAB to expand to a begin_src tag.
(use-package org-tempo
:ensure nil
:after org)
Eat(Emulate A Terminal) is a terminal emulator within Emacs. It’s more portable and less overhead for users over like vterm or eshell. We setup eat with eshell, if you want to use bash, zsh etc., check out their git repository how to do it.
(use-package eat
:hook ('eshell-load-hook #'eat-eshell-mode))
Adds the lisp directory to emacs’s load path to search for elisp files. This is necessary, because emacs does not search the entire user-emacs-directory. The directory name can be anything, just add it to the load-path.
;; (add-to-list 'load-path (expand-file-name "lisp" user-emacs-directory))
To use the elisp files we need to load it. Notes:
- Don’t forget the file and the provide name needs to be the same.
- When naming elisp files, functions, it is recommended to use a group name (e.g init-, start- or any custom name), so it does not get mixed up with other names, functions.
;; (require 'start-multiFileExample)
And now we can use everything from that file.
;; (start/hello)
All the package setups that don’t need much tweaking.
For icons and more helpful UI. This is an icon set that can be used with dired, ibuffer and other Emacs programs.
Don’t forget to use nerd-icons-install-fonts.
We use Nerd icons because it has more, better icons and all-the-icons only supports GUI. While nerd-icons supports both GUI and TUI.
(use-package nerd-icons
:if (display-graphic-p))
(use-package nerd-icons-dired
:hook (dired-mode . (lambda () (nerd-icons-dired-mode t))))
(use-package nerd-icons-ibuffer
:hook (ibuffer-mode . nerd-icons-ibuffer-mode))
Complete text-based user interface to Git.
(use-package magit
:commands magit-status)
Highlights uncommitted changes on the left side of the window (area also known as the “gutter”), allows you to jump between and revert them selectively.
(use-package diff-hl
:hook ((dired-mode . diff-hl-dired-mode-unless-remote)
(magit-pre-refresh . diff-hl-magit-pre-refresh)
(magit-post-refresh . diff-hl-magit-post-refresh))
:init (global-diff-hl-mode))
Enhances in-buffer completion with a small completion popup. Corfu is a small package, which relies on the Emacs completion facilities and concentrates on providing a polished completion. For more configuration options check out their git repository. Notes:
- To enter Orderless field separator, use M-SPC.
(use-package corfu
;; Optional customizations
:custom
(corfu-cycle t) ;; Enable cycling for `corfu-next/previous'
(corfu-auto t) ;; Enable auto completion
(corfu-auto-prefix 2) ;; Minimum length of prefix for auto completion.
(corfu-popupinfo-mode t) ;; Enable popup information
(corfu-popupinfo-delay 0.5) ;; Lower popupinfo delay to 0.5 seconds from 2 seconds
(corfu-separator ?\s) ;; Orderless field separator, Use M-SPC to enter separator
;; (corfu-quit-at-boundary nil) ;; Never quit at completion boundary
;; (corfu-quit-no-match nil) ;; Never quit, even if there is no match
;; (corfu-preview-current nil) ;; Disable current candidate preview
;; (corfu-preselect 'prompt) ;; Preselect the prompt
;; (corfu-on-exact-match nil) ;; Configure handling of exact matches
;; (corfu-scroll-margin 5) ;; Use scroll margin
(completion-ignore-case t)
;; Enable indentation+completion using the TAB key.
;; `completion-at-point' is often bound to M-TAB.
(tab-always-indent 'complete)
(corfu-preview-current nil) ;; Don't insert completion without confirmation
;; Recommended: Enable Corfu globally. This is recommended since Dabbrev can
;; be used globally (M-/). See also the customization variable
;; `global-corfu-modes' to exclude certain modes.
:init
(global-corfu-mode))
(use-package nerd-icons-corfu
:after corfu
:init (add-to-list 'corfu-margin-formatters #'nerd-icons-corfu-formatter))
Provides Completion At Point Extensions which can be used in combination with Corfu, Company or the default completion UI. Notes:
- The functions that are added later will be the first in the completion list.
- Take care when adding Capfs (Completion-at-point-functions) to the list since each of the Capfs adds a small runtime cost.
Read the configuration section in Cape’s readme for more information.
(use-package cape
:after corfu
:init
;; Add to the global default value of `completion-at-point-functions' which is
;; used by `completion-at-point'. The order of the functions matters, the
;; first function returning a result wins. Note that the list of buffer-local
;; completion functions takes precedence over the global list.
;; The functions that are added later will be the first in the list
(add-to-list 'completion-at-point-functions #'cape-dabbrev) ;; Complete word from current buffers
(add-to-list 'completion-at-point-functions #'cape-dict) ;; Dictionary completion
(add-to-list 'completion-at-point-functions #'cape-file) ;; Path completion
(add-to-list 'completion-at-point-functions #'cape-elisp-block) ;; Complete elisp in Org or Markdown mode
(add-to-list 'completion-at-point-functions #'cape-keyword) ;; Keyword/Snipet completion
;;(add-to-list 'completion-at-point-functions #'cape-abbrev) ;; Complete abbreviation
;;(add-to-list 'completion-at-point-functions #'cape-history) ;; Complete from Eshell, Comint or minibuffer history
;;(add-to-list 'completion-at-point-functions #'cape-line) ;; Complete entire line from current buffer
;;(add-to-list 'completion-at-point-functions #'cape-elisp-symbol) ;; Complete Elisp symbol
;;(add-to-list 'completion-at-point-functions #'cape-tex) ;; Complete Unicode char from TeX command, e.g. \hbar
;;(add-to-list 'completion-at-point-functions #'cape-sgml) ;; Complete Unicode char from SGML entity, e.g., &alpha
;;(add-to-list 'completion-at-point-functions #'cape-rfc1345) ;; Complete Unicode char using RFC 1345 mnemonics
)
Completion style that divides the pattern into space-separated components, and matches candidates that match all of the components in any order. Recomended for packages like vertico, corfu.
(use-package orderless
:custom
(completion-styles '(orderless basic))
(completion-category-overrides '((file (styles basic partial-completion)))))
- Vertico: Provides a performant and minimalistic vertical completion UI based on the default completion system.
- Savehist: Saves completion history.
- Marginalia: Adds extra metadata for completions in the margins (like descriptions).
- Nerd-icons-completion: Adds icons to completion candidates using the built in completion metadata functions.
We use this packages, because they use emacs native functions. Unlike Ivy or Helm. One alternative is ivy and counsel, check out the project wiki for more inforomation.
(use-package vertico
:init
(vertico-mode))
(savehist-mode) ;; Enables save history mode
(use-package marginalia
:after vertico
:init
(marginalia-mode))
(use-package nerd-icons-completion
:after marginalia
:config
(nerd-icons-completion-mode)
:hook
('marginalia-mode-hook . 'nerd-icons-completion-marginalia-setup))
Provides search and navigation commands based on the Emacs completion function. Check out their git repository for more awesome functions.
(use-package consult
;; Enable automatic preview at point in the *Completions* buffer. This is
;; relevant when you use the default completion UI.
:hook (completion-list-mode . consult-preview-at-point-mode)
:init
;; Optionally configure the register formatting. This improves the register
;; preview for `consult-register', `consult-register-load',
;; `consult-register-store' and the Emacs built-ins.
(setq register-preview-delay 0.5
register-preview-function #'consult-register-format)
;; Optionally tweak the register preview window.
;; This adds thin lines, sorting and hides the mode line of the window.
(advice-add #'register-preview :override #'consult-register-window)
;; Use Consult to select xref locations with preview
(setq xref-show-xrefs-function #'consult-xref
xref-show-definitions-function #'consult-xref)
:config
;; Optionally configure preview. The default value
;; is 'any, such that any key triggers the preview.
;; (setq consult-preview-key 'any)
;; (setq consult-preview-key "M-.")
;; (setq consult-preview-key '("S-<down>" "S-<up>"))
;; For some commands and buffer sources it is useful to configure the
;; :preview-key on a per-command basis using the `consult-customize' macro.
;; (consult-customize
;; consult-theme :preview-key '(:debounce 0.2 any)
;; consult-ripgrep consult-git-grep consult-grep
;; consult-bookmark consult-recent-file consult-xref
;; consult--source-bookmark consult--source-file-register
;; consult--source-recent-file consult--source-project-recent-file
;; :preview-key "M-."
;; :preview-key '(:debounce 0.4 any))
;; By default `consult-project-function' uses `project-root' from project.el.
;; Optionally configure a different project root function.
;;;; 1. project.el (the default)
;; (setq consult-project-function #'consult--default-project--function)
;;;; 2. vc.el (vc-root-dir)
;; (setq consult-project-function (lambda (_) (vc-root-dir)))
;;;; 3. locate-dominating-file
;; (setq consult-project-function (lambda (_) (locate-dominating-file "." ".git")))
;;;; 4. projectile.el (projectile-project-root)
(autoload 'projectile-project-root "projectile")
(setq consult-project-function (lambda (_) (projectile-project-root)))
;;;; 5. No project support
;; (setq consult-project-function nil)
)
This package implements hiding or abbreviation of the modeline displays (lighters) of minor-modes. With this package installed, you can add ‘:diminish’ to any use-package block to hide that particular mode in the modeline.
(use-package diminish)
Adds colors to brackets.
(use-package rainbow-delimiters
:hook (prog-mode . rainbow-delimiters-mode))
Which-key is a helper utility for keychords (which key to press).
(use-package which-key
:init
(which-key-mode 1)
:diminish
:custom
(which-key-side-window-location 'bottom)
(which-key-sort-order #'which-key-key-order-alpha) ;; Same as default, except single characters are sorted alphabetically
(which-key-sort-uppercase-first nil)
(which-key-add-column-padding 1) ;; Number of spaces to add to the left of each column
(which-key-min-display-lines 6) ;; Increase the minimum lines to display, because the default is only 1
(which-key-idle-delay 0.8) ;; Set the time delay (in seconds) for the which-key popup to appear
(which-key-max-description-length 25)
(which-key-allow-imprecise-window-fit nil)) ;; Fixes which-key window slipping out in Emacs Daemon
Dial the GC threshold back down so that garbage collection happens more frequently but in less time. We also increase Read Process Output Max so emacs can read more data.
;; Make gc pauses faster by decreasing the threshold.
(setq gc-cons-threshold (* 2 1000 1000))
;; Increase the amount of data which Emacs reads from the process
(setq read-process-output-max (* 1024 1024)) ;; 1mb