This is my config. It does just about everything I need it to do, and a lot more than that too. I run emacs 28 which is why it’s included as a submodule. It has been running rocksolid since forever.
Just to let you know. If you want to use it, or parts of it, be my guest. All of the configuration is in config.org. I’ve been very sparse with comments, but the headings should be pretty descriptive, however if you’re looking for something in there, just <C-f>
, <C-s>
, /
or what ever you do.
I’m running this config for work with emacs 28.0.50, and thus I cannot guarentee but might work with previous versions without modification, or it might not.
To use it, just clone this repo to whereever your emacs config is (usually /home/$(USER)/.emacs.d
) and remember to back up your old one, if you have one. You can then try it with whatever version of Emacs you have installed to see if it works. But as mentioned, it’s only been tested with Emacs 28.0.50, meaning you’d have to either build it from source, or fetch a binary from your local software pusher (soure can be found here https://git.savannah.gnu.org/git/emacs.git).
Also, I’m NOT responsible for anything that happens to anything that touches these files.
Setting up the basics early, so if the config breaks further along, I’ll still have evil also, setting some code block properties that help.
I use straight for managing packages. It’s a very painless process to spin up a new machine, just by downloading the repo and starting up emacs. The config for this can be found in init.el.
Yes, I also came from [neo]vi[m], so ofc evil is gonna be in here. These are some nice packages that relate to evil, however there are “evil-*” packages more throughout the file
(setq evil-want-integration t
evil-want-keybinding nil
evil-want-C-i-jump nil)
(use-package evil-leader
:init
(global-evil-leader-mode)
(evil-leader/set-leader "<SPC>"))
(use-package evil-collection
:after evil-leader
:custom
(evil-collection-company-use-tng nil)
:init
(evil-collection-init))
(use-package evil
:after evil-collection
:custom (evil-undo-system 'undo-tree)
:init
(evil-mode 1))
(use-package evil-anzu)
(use-package evil-surround
:config
(global-evil-surround-mode))
(use-package evil-owl
:custom
(evil-owl-display-method 'posframe)
(evil-owl-extra-posfram-args '(:width 50 :height 20))
(evil-owl-idle-delay 0)
:init
(evil-owl-mode))
(use-package evil-matchit)
(use-package evil-avy
:mode (prog-mode . evil-avy-mode))
misc default settings
(setq-default scroll-conservatively 100
inhibit-startup-message t
initial-scratch-message ""
indent-tabs-mode nil
ring-bell-function 'ignore
tab-width 4
create-lockfiles nil
default-directory (expand-file-name "~/")
tramp-default-method "ssh"
large-file-warning-threshold nil
custom-file (expand-file-name "customs.el" user-emacs-directory)
delete-trailing-lines t
tramp-smb-conf nil
windmove-wrap-around t
c-basic-offset 4)
(add-hook 'prog-mode-hook
(lambda ()
(make-local-variable 'scroll-margin)
(setq scroll-margin 20)))
(use-package undo-tree
:config (global-undo-tree-mode))
(defvaralias 'c-basic-offset 'tab-width)
(defalias 'yes-or-no-p 'y-or-n-p)
(defvaralias 'c-basic-offset 'tab-width)
(global-subword-mode)
(tool-bar-mode -1)
(menu-bar-mode -1)
(scroll-bar-mode -1)
(add-hook 'prog-mode-hook 'display-line-numbers-mode)
(setq shell-file-name "bash")
(setq shell-command-switch "-c")
(setq auto-save-visited-file-name t)
;; Autorevert buffers
(global-auto-revert-mode)
;; File beautification
(add-hook 'before-save-hook 'delete-trailing-whitespace)
;; Electricity!!
(add-hook 'prog-mode-hook 'electric-pair-mode)
;; environments
(use-package exec-path-from-shell
:config (exec-path-from-shell-initialize))
;; make tramp play nice
(eval-after-load 'tramp '(setenv "SHELL" "/bin/bash"))
;; File beautification
(setq delete-trailing-lines t)
(add-hook 'before-save-hook 'delete-trailing-whitespace)
;; font
(add-to-list 'default-frame-alist '(font . "Iosevka Nerd Font 10"))
(use-package helm
:init
(require 'helm-config)
(helm-mode)
:custom
(helm-mini-default-sources
'(helm-source-buffers-list
helm-source-buffer-not-found)))
(use-package helm-company)
(use-package helm-projectile)
(use-package helm-rg)
(use-package helm-fzf
:straight (helm-fzf :type git :host github :repo "ibmandura/helm-fzf"))
(use-package helm-make
:custom
(helm-make-build-dir "build"))
(use-package helm-flyspell)
(add-hook 'org-mode-hook 'flyspell-mode)
(add-hook 'markdown-mode-hook 'flyspell-mode)
(use-package helm-lsp)
(use-package elfeed
:custom
(elfeed-feeds
'(
;;dr.dk
"https://www.dr.dk/nyheder/service/feeds/allenyheder"
;;ing.dk
"https://ing.dk/rss/nyheder"
;;dev.to
"http://dev.to/feed"
;;reddit
"http://reddit.com/r/clojure/.rss"
"http://reddit.com/r/cpp/.rss"
"http://reddit.com/r/emacs/.rss"
"http://reddit.com/r/golang/.rss"
"http://reddit.com/r/rust/.rss"
"http://reddit.com/r/bindingofisaac/.rss"
;;hackernews
"https://news.ycombinator.com/rss"
;;medium
"https://medium.com/feed/topic/technology"
"https://medium.com/feed/topic/programming"
"https://medium.com/feed/topic/gaming"
;;other blogs
"https://cestlaz.github.io/rss.xml"
)))
(when (file-exists-p "/usr/share/emacs/site-lisp/mu4e")
(add-to-list 'load-path "/usr/share/emacs/site-lisp/mu4e")
(require 'mu4e)
(use-package mu4e-alert))
(use-package dashboard
:config
(dashboard-setup-startup-hook)
:custom
;; set initial buffer for emacsclient
(initial-buffer-choice (lambda () (get-buffer "*dashboard*")))
(dashboard-banner-logo-title "")
(dashboard-startup-banner (expand-file-name "banner.png" user-emacs-directory))
(dashboard-center-content t))
magit is the best git client in the multiverse. I use the evil variant.
(use-package evil-magit
:init
(evil-magit-init)
:custom
(magit-repository-directories (expand-file-name "~/git/projects"))
(magit-module-sections-nested nil))
(magit-add-section-hook 'magit-status-sections-hook
'magit-insert-modules
'magit-insert-unpulled-from-upstream)
As well as some other packages that relate
(use-package forge)
(use-package ssh-agency)
Tools for more git integration. Git timemachine let’s you check the git log in the buffer and is extremely useful git gutter are the plus and minus signs that show you what’s added/removed/changed on the left
(use-package git-timemachine)
(use-package git-gutter-fringe+
:config
(global-git-gutter+-mode)
(git-gutter-fr+-minimal))
(defun dired-run-at-point ()
(interactive)
(let ((process (dired-file-name-at-point)))
(async-start-process (file-name-base process) process '(lambda (arg)))))
(dired-async-mode 1)
As long as it lasts
(defun p4-edit-file ()
(interactive)
(call-process-shell-command (format "p4 edit %s" (buffer-file-name)))
(revert-buffer t t nil))
(defun p4-revert-file ()
(interactive)
(call-process-shell-command (format "p4 revert %s" (buffer-file-name)))
(revert-buffer t t nil))
(defun p4-add-file ()
(interactive)
(call-process-shell-command (format "p4 add %s" (buffer-file-name)))
(revert-buffer t t nil))
(defun p4-integrate-file ()
(interactive)
(call-process-shell-command (format "p4 integrate %s" (buffer-file-name)))
(revert-buffer t t nil))
(defun p4-diff-file ()
(interactive)
(let ((buffer "*p4-diff*"))
(call-process-shell-command (format "p4 diff %s" (buffer-file-name)) nil buffer)
(switch-to-buffer buffer)
(diff-mode)
(view-mode-enter nil 'kill-buffer)))
Quality of life packages. many require external software. Look at each package for dependecies
used to search web resources.
(use-package engine-mode
:straight (:branch "main")
:config
(defengine cppreference
"https://en.cppreference.com/mwiki/index.php?search=%s")
(defengine cmake
"https://cmake.org/cmake/help/latest/search.html?q=%s&check_keywords=yes&area=default")
(defengine google
"https://google.com/search?q=%s")
(defengine youtube
"https://www.youtube.com/results?search_query=%s")
(defengine dockerhub
"https://hub.docker.com/search?q=%s&type=image")
(defengine github
"https://github.com/search?q=%s")
(defengine rustdoc
"https://doc.rust-lang.org/rustdoc/what-is-rustdoc.html?search=%s")
(defengine wikipedia
"https://en.wikipedia.org/wiki/%s"))
(use-package sudo-edit)
(use-package docker)
(straight-use-package '(dockerfile-mode :type git :repo "fredeeb/dockerfile-mode"))
(setq dockerfile-use-buildkit t)
(use-package docker-compose-mode
:mode ("docker-compose.yml\\'" . docker-compose-mode))
(use-package docker-tramp
:config (add-to-list 'tramp-remote-path 'tramp-own-remote-path))
requires zathura for pdf reading. feh for image viewing (not all formats are tested).
(use-package openwith
:config
(openwith-mode t)
:custom
(openwith-associations
'(("\\.pdf\\'" "zathura" (file))
("\\.jpg\\'" "feh" (file))
("\\.svg\\'" "feh" (file))
("\\.jpeg\\'" "feh" (file))
("\\.bmp\\'" "feh" (file))
("\\.flac\\'" "mpv" (file))
("\\.mkv\\'" "mpv" (file))
("\\.wav\\'" "mpv" (file))
("\\.mp3\\'" "mpv" (file))
("\\.mp4\\'" "mpv" (file)))))
(use-package vterm
:custom
(vterm-shell "zsh")
:custom
(vterm-always-compile-module t))
(setq compilation-scroll-output t
compilation-window-height 20)
(require 'ansi-color)
(defun colorize-compilation ()
"Colorize from `compilation-filter-start' to `point'."
(let ((inhibit-read-only t))
(ansi-color-apply-on-region
compilation-filter-start (point))))
(add-hook 'compilation-filter-hook
#'colorize-compilation)
;; C++
;; set ctest to output on failure
(setenv "CTEST_OUTPUT_ON_FAILURE" "1")
(defun compile-c++-things ()
(interactive)
(if-let* ((root (vc-root-dir))
(cmake (concat root "/CMakeLists.txt"))
(build (concat root "/build")))
(call-process "cmake" nil nil nil "-S" root "-B" build)
(message "Not in a repository"))
(helm-make-projectile (string-to-number (first (process-lines "nproc")))))
I’ve created a personal journal system that creates a new journal entry in journal-dir
every day. This file is the default target for org agenda entries created with M-x org-capture t
and M-x org-capture n
for TODO items under TODAY and miscellaneous notes under the NOTES header, respectively.
Issues with questions or bugs and PR’s are welcome, but I only fix/merge things i feel improves my workflow.
(defvar journal-dir
(expand-file-name"~/journals/"))
(defvar journal
(format "%sjournal%s.org"
journal-dir
(format-time-string "%Y%m%d")))
(defvar org-journal-template
(concat
"#+TITLE: Journal\n"
"#+DATE: " (format-time-string "%A %d/%m/%Y\n")
"* TODAY\n"
"* NOTES"))
(defun find-journal (days-ago)
"Find journal from DAYS-AGO"
(interactive "p")
(if (not current-prefix-arg)
(find-file
journal)
(find-file
(concat
journal-dir
"journal"
(format-time-string
"%Y%m%d"
(seconds-to-time (- (time-to-seconds) (* days-ago 86400))))
".org"))))
Setting org todo keyword and agenda templates
(setq org-todo-keywords
'((sequence "TODO(t)" "DOING(p)" "|" "DONE(d)" "|" "NOT FINISHED(n)"))
org-columns-default-format
"%25ITEM %TODO %DEADLINE %EFFORT %TAGS"
org-capture-templates
'(("t" "Todo" entry (file+headline journal "TODAY")
"** TODO %?\n")
("n" "Note" entry (file+headline journal "NOTES")
"** %?\n\n")))
Modes and settings for org source blocks
(use-package ob-async)
(use-package ob-rust)
(require 'org-tempo)
(setq org-confirm-babel-evaluate nil
org-startup-with-inline-images t
org-startup-with-latex-preview t
org-export-babel-evaluate nil)
(org-babel-do-load-languages
'org-babel-load-languages
'((C . t)
(calc . t)
(clojure . t)
(emacs-lisp . t)
(js . t)
(makefile . t)
(plantuml . t)
(python . t)
(rust . t)
(shell . t)))
pretty things
(add-hook 'org-mode-hook 'visual-line-mode)
(add-hook 'markdown-mode-hook 'visual-line-mode)
(use-package org-bullets
:config
(add-hook 'org-mode-hook (lambda () (org-bullets-mode 1))))
company completes anything and it works wonderfully
(use-package company
:hook ((prog-mode docker-compose-mode) . company-mode)
:custom
(company-idle-delay 0)
(company-minimum-prefix-length 1)
(company-tooltip-align-annotations t)
(company-tooltip-limit 10)
(company-idle-delay 0)
(company-echo-delay (if (display-graphic-p) nil 0))
(company-minimum-prefix-length 2)
(company-require-match 'never)
(company-show-numbers t)
(company-global-modes '(not erc-mode message-mode help-mode gud-mode eshell-mode shell-mode))
(company-backends '(company-capf)))
(use-package company-box
:hook (company-mode . company-box-mode))
(use-package company-posframe
:config
(company-posframe-mode)
:custom
(company-posframe-quickhelp-delay nil))
(use-package flycheck)
(use-package lsp-mode
:hook
((c++-mode c-mode rust-mode go-mode csharp-mode python-mode cmake-mode) . lsp)
:custom
(lsp-diagnostic-package :flycheck)
(lsp-prefer-capf t)
(read-process-output-max (* 1024 1024)))
(use-package lsp-ui
:custom
(lsp-ui-doc-max-width 80)
(lsp-ui-doc-position 'top))
(use-package lsp-treemacs)
(use-package dap-mode
:init
(require 'dap-gdb-lldb)
(require 'dap-go)
;;download debuggers, REQUIRES unzip
(when (not (file-exists-p (expand-file-name ".extension" user-emacs-directory)))
(dap-gdb-lldb-setup t)
(dap-go-setup t)))
All the lispy things
(use-package evil-paredit
:hook
(emacs-lisp-mode-hook . evil-paredit-mode)
(emacs-lisp-mode-hook . paredit-mode))
;; elisp
(use-package elsa)
(use-package eros
:hook (eros-mode . emacs-lisp-mode))
(use-package pipenv
:hook (python-mode . pipenv-mode)
:custom
(pipenv-projectile-after-switch-function #'pipenv-projectile-after-switch-extended))
this is what I use most in this configuration
(c-set-offset 'substatement-open 0)
(c-set-offset 'innamespace 0)
(c-set-offset 'brace-list-open 0)
(setq c-basic-offset 4)
(setq lsp-clients-clangd-args
'("-j=8"
"--header-insertion=never"
"--all-scopes-completion"
"--background-index"
"--clang-tidy"
"--compile-commands-dir=build"
"--cross-file-rename"
"--suggest-missing-includes"))
(use-package modern-cpp-font-lock
:config
(modern-c++-font-lock-global-mode))
(use-package cmake-mode)
(use-package cargo
:hook (rust-mode . cargo-minor-mode)
:custom
(lsp-rust-server 'rust-analyzer))
(use-package toml-mode)
(use-package lua-mode
:mode ("\\.lua\\'")
:hook (lua-mode . lsp))
(use-package go-mode
:config
(push (expand-file-name "~/go/bin") exec-path))
(defun go-run ()
(interactive)
(save-buffer)
(let ((buffer "*go*"))
(start-process "*go*" buffer "go" "run" (buffer-name))
(switch-to-buffer buffer)
(view-mode)))
(use-package emmet-mode
:custom
(emmet-expand-jsx-className t))
(use-package web-mode
:mode ("\\.ts\\'" "\\.tsx\\'" "\\.js\\'" "\\.jsx\\'")
:hook (web-mode . lsp))
(use-package restclient)
(use-package ob-restclient)
All the snippets! (or atleast most of them)
(use-package yasnippet-snippets)
(use-package react-snippets)
(use-package yasnippet
:init
(yas-global-mode 1))
(use-package auto-yasnippet)
(defun company-yasnippet-or-completion ()
(interactive)
(let ((yas-fallback-behavior nil))
(unless (yas-expand)
(call-interactively #'company-complete-common))))
(add-hook 'company-mode-hook
(lambda () (substitute-key-definition
'company-complete-common
'company-yasnippet-or-completion
company-active-map)))
(use-package yaml-mode)
(use-package json-mode)
(use-package protobuf-mode)
;; (use-package gnuplot)
insert stdout from terminal (try “Q” on the next line) seq 0 255 | xargs printf “%.2x\n” | fmt -w 49
(defun insert-output-of-executed-line ()
"executes line at point in default shell and inserts stdout"
(interactive)
(insert
(shell-command-to-string
(delete-and-extract-region
(point-at-bol)
(point-at-eol)))))
shell-pop for temporary shells
(use-package shell-pop
:custom
(shell-pop-shell-type '("terminal" "*Terminal*" 'eshell))
(shell-pop-window-position "bottom"))
(use-package polymode)
(use-package poly-markdown
:hook (markdown-mode . poly-markdown-mode))
(use-package poly-org
:hook (org-mode . poly-org-mode))
The theme is a custom version of doom dracula
(use-package doom-themes
:init
(load-theme 'doom-dracula t)
:config
(custom-set-faces
'(button ((t (:inherit link :foreground "#ffb86c" :underline nil))))
'(font-lock-comment-face ((t (:foreground "#6272a4" :slant italic))))
'(font-lock-preprocessor-face ((t (:inherit nil :foreground "#bd93f9"))))
'(variable-pitch ((t (:family "Fira Sans"))))))
I also use doom-modeline cause it looks damn good
(use-package doom-modeline
:hook (after-init . doom-modeline-init)
:custom
(doom-modeline-buffer-file-name-style 'relative-from-project)
(doom-modeline-height 35)
(doom-modeline-bar-width 4)
(doom-modeline-icon t)
(doom-modeline-major-mode-icon t)
(doom-modeline-major-mode-color-icon nil))
Solaire mode is awesome for introducing a few extra shades of gray
(use-package solaire-mode
:init
(solaire-global-mode))
Whichkey is for when I can’t remember the keys I’m supposed to press
(use-package which-key
:init
(which-key-mode))
;; Leader keys
(evil-leader/set-key
;;buffers & windows
"b" 'helm-buffers-list
"y" 'helm-show-kill-ring
"o" 'other-window
"q" 'kill-buffer-and-window
"h" 'windmove-left
"j" 'windmove-down
"k" 'windmove-up
"l" 'windmove-right
;;misc
"a" 'comment-dwim
"i" 'indent-region
;;buffer
"<SPC>" 'evil-avy-goto-char-timer
"e" 'ediff-buffers
"u" 'calc-embedded
;;files
"f f" 'treemacs-select-window
"f d" 'dired-jump
"f t" '(lambda () (interactive) (find-file "/tmp"))
"f e" '(lambda () (interactive) (find-file (expand-file-name "config.org" user-emacs-directory)))
"f z" '(lambda () (interactive) (find-file (expand-file-name "~/.zshrc")))
"f p" '(lambda () (interactive) (find-file (expand-file-name "~/src/")))
"f i" '(lambda () (interactive) (find-file (expand-file-name "~/.config/")))
"f h" '(lambda () (interactive) (find-file (expand-file-name "~/")))
"f n" '(lambda () (interactive) (find-file (expand-file-name "notes.org" (vc-root-dir))))
"f d" 'dired-jump
"f j" 'find-journal
;;config reload
"f r" '(lambda () (interactive) (load-file (expand-file-name "init.el" user-emacs-directory)))
;;Git
"g s" 'magit-status
"g t" 'git-timemachine
"g f" 'global-git-gutter+-mode
"g g" 'helm-projectile-grep
"g r" 'git-gutter+-revert-hunk
"g m" 'magit-blame-addition
;;elfeed
"n" 'elfeed
;;lsp
"r d" 'lsp-ui-peek-find-definitions
"r e" 'lsp-execute-code-action
"r o" 'lsp-rename
"r r" 'lsp-ui-peek-find-references
"r s" 'helm-lsp-workspace-symbol
"r l" 'lsp-treemacs-errors-list
"r i" 'lsp-format-region
"r b" 'lsp-format-buffer
;;dap
"d r" 'dap-debug-restart
"d l" 'dap-debug-last
"d f" 'dap-debug-recent
"d d" 'dap-debug
"d t" 'dap-debug-edit-template
"d h" '(lambda () (interactive) (dap-ui-mode t) (dap-hydra))
;;compile
"c" 'helm-make-projectile
;;find stuff
"p a" 'helm-projectile-rg
;;Docker
"g d" 'docker
"g c" 'docker-compose
;;utilities
"+" 'calc
"-" 'mu4e
"<RET>" 'vterm
;;projectile
"p p" 'helm-projectile
"p f" 'helm-projectile-find-file-dwim
"p s" 'projectile-add-known-project
"p c" 'projectile-compile-project
"v m" '(lambda () (interactive) (find-file "./CMakeLists.txt"))
"v d" '(lambda () (interactive) (find-file "./Dockerfile"))
"v c" '(lambda () (interactive) (find-file "./docker-compose.yml"))
"v p" '(lambda () (interactive) (find-file "./Pipfile"))
;;engine
"s c" 'engine/search-cppreference
"s b" 'engine/search-cmake
"s y" 'engine/search-youtube
"s d" 'engine/search-dockerhub
"s r" 'engine/search-rustdoc
"s w" 'engine/search-wikipedia
"s g i" 'engine/search-github
"s g o" 'engine/search-google
;; window management
"w w" 'tear-off-window
"w h" 'windmove-swap-states-left
"w j" 'windmove-swap-states-down
"w k" 'windmove-swap-states-up
"w l" 'windmove-swap-states-right)
(evil-leader/set-key-for-mode 'dired-mode
"d i" '(lambda () (interactive) (start-process "sxiv" "*sxiv*" "sxiv" (dired-filename-at-point)))
"d e" 'dired-run-at-point)
(evil-leader/set-key-for-mode 'emacs-lisp-mode
"e" 'eval-last-sexp
"k" 'eval-buffer)
(setq local-function-key-map (delq '(kp-tab . [9]) local-function-key-map))
;;global state
(evil-define-key nil global-map
(kbd "M-*") 'helm-rg
(kbd "M-r") 'recompile
(kbd "C-x C-f") 'helm-find-files
(kbd "C-x C-d") 'helm-fzf-project-root
(kbd "C-x C-b") 'helm-buffers-list
(kbd "M-x") 'helm-M-x
(kbd "M-p") 'emmet-expand-yas
(kbd "C-S-c") 'aya-create
(kbd "C-S-e") 'aya-expand
(kbd "C-s") 'save-buffer
(kbd "C-c l") 'org-store-link
(kbd "C-c a") 'org-todo-list
(kbd "C-k") 'kill-buffer-and-window
(kbd "C-c c") 'org-capture
(kbd "C-;") 'shell-pop)
(evil-define-key nil org-mode-map
(kbd "M-H") 'org-shiftleft
(kbd "M-J") 'org-shiftdown
(kbd "M-K") 'org-shiftup
(kbd "M-L") 'org-shiftright
(kbd "M-h") 'org-metaleft
(kbd "M-j") 'org-metadown
(kbd "M-k") 'org-metaup
(kbd "M-l") 'org-metaright)
(evil-define-key 'normal compilation-mode-map
(kbd "C-n") 'compilation-next-error
(kbd "C-p") 'compilation-previous-error)
(evil-define-key 'normal dired-mode-map
(kbd "Y") '(lambda () (interactive) (dired-copy-filename-as-kill 0))
(kbd "y") 'dired-copy-filename-as-kill)
(evil-define-key nil go-mode-map
(kbd "C-c C-c") 'go-run)
(evil-define-key 'normal global-map
(kbd "Q") 'insert-output-of-executed-line)
(evil-define-key 'visual global-map
(kbd "S") 'evil-surround-region)
;; paredit mode
(evil-define-key nil paredit-mode-map
(kbd "M-l") 'paredit-forward-slurp-sexp
(kbd "M-h") 'paredit-backward-slurp-sexp
(kbd "M-L") 'paredit-backward-barf-sexp
(kbd "M-H") 'paredit-forward-barf-sexp)
(evil-define-key nil cider-repl-mode-map
(kbd "C-k") 'cider-repl-backward-input
(kbd "C-j") 'cider-repl-forward-input)
(evil-define-key 'normal global-map
(kbd "U") 'undo-tree-visualize)