Skip to content

Instantly share code, notes, and snippets.

@Kintaro
Created January 6, 2023 13:37
Show Gist options
  • Save Kintaro/044691424121226c59aeaa1ee83d221f to your computer and use it in GitHub Desktop.
Save Kintaro/044691424121226c59aeaa1ee83d221f to your computer and use it in GitHub Desktop.

Literal Emacs Config

Introduction

Welcome to my literal Emacs config. This document is mostly meant to document itself and keep my configuration sane enough that I myself still understand it years down the road. But feel free to pick and choose whatever is needed. I do however not recommend to just copy the entire config, which would miss the point of building one from scratch entirely.

Resources

Prerequisites

Of course, one needs to have Emacs installed. Start it up, and then open this literate config by pressing `M-x` (ALT/Option and x together), followed by typing in `find-file` and confirming with return. Lastly, enter the path to the config file. Again, with `M-x`, run `org-babel-tangle`. Restart emacs. This only has to be done once. After that, any change to this config file will automatically tangle it on save.

early-init.el

Since Emacs 28.0, it allows to have a pre-init before `init.el`. The only thing we want to do here is to disable Emacs’ internal package manager right at the start.

early-init.el

Add the following to `early-init.el`

;;; early-init.el --- Early Init File -*- lexical-binding: t; no-byte-compile: t -*-

(setq package-enable-at-startup nil)

init.el

I don’t want to use init.el to configure Emacs. I want to use an org file to config Emacs because I like literate configs with lots of comments. The following code block should be your init.el. This tells init.el to use the source code blocks from this file (config.org).

About this config

This is my personal literate emacs config, based losely on doom emacs.

Package Manager

This config uses `straight` instead of `use-package`.

(setq straight-use-package-by-default t)
(setq straight-vc-git-default-clone-depth 1)
(setq straight-recipes-gnu-elpa-use-mirror t)
(setq straight-check-for-modifications nil)
(setq use-package-always-defer t)
(defvar bootstrap-version)
(let ((bootstrap-file
       (expand-file-name "straight/repos/straight.el/bootstrap.el" user-emacs-directory))
      (bootstrap-version 6))
  (unless (file-exists-p bootstrap-file)
    (with-current-buffer
        (url-retrieve-synchronously
         "https://raw.githubusercontent.com/radian-software/straight.el/develop/install.el"
         'silent 'inhibit-cookies)
      (goto-char (point-max))
      (eval-print-last-sexp)))
  (load bootstrap-file nil 'nomessage))
(straight-use-package 'use-package)
(setq comk-deferred-compilation-black-list nil)

Minor pre-amble

(setq make-backup-files nil)

Evil Mode

Can’t live without VIM bindings. Luckily emacs has evil mode, which provides these for us.

(use-package evil
  :demand
  :init
  (setq evil-want-integration t)
  (setq evil-want-keybinding nil)
  (setq evil-vsplit-window-right t)
  (setq evil-split-window-below t)
  (setq evil-want-C-u-scroll t)
  (setq evil-want-C-i-jump nil)
  (setq evil-want-Y-yank-to-eol t)
  :config
  (evil-mode 1))
(use-package evil-collection
  :after evil
  :demand
  :config
  ;;(setq evil-collection-mode-list '(dashboard dired ibuffer neotree))
  (evil-collection-init))
(use-package evil-tutor :demand)

“General” for keybindings

A package allowing to create custom keybindings in a quick and convenient way.

(use-package general
  :demand
  :config
  (general-evil-setup t))
(use-package general
  :demand t
  :config
  (general-evil-setup)

  (general-create-definer lc/leader-keys
    :states '(normal insert visual emacs)
    :keymaps 'override
    :prefix "SPC"
    :global-prefix "C-SPC")

  (general-create-definer lc/local-leader-keys
    :states '(normal visual)
    :keymaps 'override
    :prefix ","
    :global-prefix "SPC m")
)

File Manager

(use-package all-the-icons-dired :demand)
(use-package dired-open :demand)
(use-package peep-dired :demand)

(nvmap :states '(normal visual) :keymaps 'override :prefix "SPC"
               "d d" '(dired :which-key "Open dired")
               "d j" '(dired-jump :which-key "Dired jump to current")
               "d p" '(peep-dired :which-key "Peep-dired"))

(with-eval-after-load 'dired
  ;;(define-key dired-mode-map (kbd "M-p") 'peep-dired)
  (evil-define-key 'normal dired-mode-map (kbd "h") 'dired-up-directory)
  (evil-define-key 'normal dired-mode-map (kbd "l") 'dired-open-file) ; use dired-find-file instead if not using dired-open package
  (evil-define-key 'normal peep-dired-mode-map (kbd "j") 'peep-dired-next-file)
  (evil-define-key 'normal peep-dired-mode-map (kbd "k") 'peep-dired-prev-file))

(add-hook 'peep-dired-hook 'evil-normalize-keymaps)
;; Get file icons in dired
(add-hook 'dired-mode-hook 'all-the-icons-dired-mode)

With dired-open plugin, you can launch external programs for certain extensions For example, I set all .png files to open in ‘sxiv’ and all .mp4 files to open in ‘mpv’

(setq dired-open-extensions '(("gif" . "sxiv")
                              ("jpg" . "sxiv")
                              ("png" . "sxiv")
                              ("mkv" . "mpv")
                              ("mp4" . "mpv")))

Keybindings

These keybindings mimic the default bindings in doom emacs a lot since I got used to them.

(nvmap :states '(normal visual) :keymaps 'override :prefix "SPC"
       "."     '(find-file :which-key "Find file")
       "f f"   '(find-file :which-key "Find file")
       "f r"   '(counsel-recentf :which-key "Recent files")
       "f s"   '(save-buffer :which-key "Save file")
       "f u"   '(sudo-edit-find-file :which-key "Sudo find file")
       "f y"   '(dt/show-and-copy-buffer-path :which-key "Yank file path")
       "f C"   '(copy-file :which-key "Copy file")
       "f D"   '(delete-file :which-key "Delete file")
       "f R"   '(rename-file :which-key "Rename file")
       "f S"   '(write-file :which-key "Save file as...")
       "f U"   '(sudo-edit :which-key "Sudo edit file"))
(use-package counsel
  :after ivy
  :demand
  :config (counsel-mode))
(use-package recentf
  :demand
  :config
  (recentf-mode))
(use-package sudo-edit :demand)

UI Tweaks

Remove unnecessary UI stuff

Remove things like Menu, toolbar, …

(menu-bar-mode -1)
(tool-bar-mode -1)
(scroll-bar-mode -1)

Enable the good stuff

(global-display-line-numbers-mode 1)
(setq display-line-numbers-type 'relative)
(global-visual-line-mode t)

Change Modeline To Doom’s Modeline

(use-package doom-modeline 
  :demand
  :init
  (doom-modeline-mode 1))

Dashboard

(use-package dashboard
  :demand
  :init      ;; tweak dashboard config before loading it
  (setq dashboard-set-heading-icons t)
  (setq dashboard-set-file-icons t)
  (setq dashboard-banner-logo-title "Emacs Is Org-Mode and Org-Mode is life!")
  (setq dashboard-center-content nil) ;; set to 't' for centered content
  (setq dashboard-items '((recents . 5)
		    (agenda . 5 )
		    (bookmarks . 3)
		    (projects . 3)
		    (registers . 3)))
  :config
  (dashboard-setup-startup-hook)
  (dashboard-modify-heading-icons '((recents . "file-text")
				(bookmarks . "book"))))

Fonts

Defining our fonts. Right now I’m using Source Code Pro (SauceCodePro) from the nerd-fonts repository. Installed from the AUR, it does NOT include all variations of the font (such as italics). You can download the italics Source Code Pro font from the nerd-fonts GitHub though.

Setting The Font Face

(set-face-attribute 'default nil
  ;:font "PragmataPro Liga"
  :font "Roboto Mono"
  :height 140
  :weight 'medium)
(set-face-attribute 'variable-pitch nil
  ;:font "PragmataPro Liga"
  :font "Roboto Mono"
  :height 140
  :weight 'medium)
(set-face-attribute 'fixed-pitch nil
  ;:font "PragmataPro Mono Liga"
  :font "Roboto Mono"
  :height 140
  :weight 'medium)
;; Makes commented text and keywords italics.
;; This is working in emacsclient but not emacs.
;; Your font must have an italic face available.
(set-face-attribute 'font-lock-comment-face nil
  :slant 'italic)
(set-face-attribute 'font-lock-keyword-face nil
  :slant 'italic)

;; Uncomment the following line if line spacing needs adjusting.
(setq-default line-spacing 0.12)

;; Needed if using emacsclient. Otherwise, your fonts will be smaller than expected.
;;(add-to-list 'default-frame-alist '(font . "PragmataPro Liga-11"))
;; changes certain keywords to symbols, such as lamda!
(setq global-prettify-symbols-mode t)

Zooming In and Out

You can use the bindings CTRL plus =/- for zooming in/out. You can also use CTRL plus the mouse wheel for zooming in/out.

;; zoom in/out like we do everywhere else.
(global-set-key (kbd "C-=") 'text-scale-increase)
(global-set-key (kbd "C--") 'text-scale-decrease)
(global-set-key (kbd "<C-wheel-up>") 'text-scale-increase)
(global-set-key (kbd "<C-wheel-down>") 'text-scale-decrease)

Rainbow delimiters

(use-package rainbow-delimiters
  :demand
  :config
  (add-hook 'prog-mode-hook 'rainbow-delimiters-mode))

Delete selection mode

By default in Emacs, we don’t have ability to select text, and then start typing and our new text replaces the selection. Let’s fix that!

(delete-selection-mode t)

NeoTree

All hail the king of trees!

(use-package neotree
  :demand
  :config
  (setq neo-smart-open t
        neo-window-width 30
        neo-theme (if (display-graphic-p) 'icons 'arrow)
        ;;neo-window-fixed-size nil
        inhibit-compacting-font-caches t)
        ;projectile-switch-project-action 'neotree-projectile-action) 
        ;; truncate long file names in neotree
        (add-hook 'neo-after-create-hook
           #'(lambda (_)
               (with-current-buffer (get-buffer neo-buffer-name)
                 (setq truncate-lines t)
                 (setq word-wrap nil)
                 (make-local-variable 'auto-hscroll-mode)
                 (setq auto-hscroll-mode nil))))

  :general
  (lc/leader-keys
    "t"   '(:wk "Toggle")
    "t n" '(neotree-toggle :wk "Toggle neotree")
    "d n" '(neotree-dir :wk "Open directory in neotree")
  ))

Indentation

(use-package dtrt-indent
  :demand)

Org mode

General

Set up our roam directory and some basic defaults

(require 'org)
(add-hook 'org-mode-hook 'org-indent-mode)
(setq org-directory "~/roam/org"
      org-log-done 'time
      org-hide-emphasis-markers t)
(setq org-src-preserve-indentation nil
      org-src-tab-acts-natively t
      org-edit-src-content-indentattion 0)
(setq org-return-follows-link t)

(setq org-todo-keywords
      '((sequence "TODO(t!)" "WAIT(@/!)" "|" "DONE(d!)" "CANCELED(c@)")))

(use-package org-contrib :demand)

(setq org-link-frame-setup
    '((file . find-file)))

(setq org-startup-with-inline-images t)

(setq org-confirm-babel-evaluate nil)

(require 'ob-shell)

(use-package ob-async :demand)
  (defun no-hide-overlays (orig-fun &rest args)
    (setq org-babel-hide-result-overlays nil))

  (advice-add 'ob-async-org-babel-execute-src-block :before #'no-hide-overlays)

(nvmap :prefix "SPC"
  "o a" '(org-agenda :wk "show agenda"))

Org Lilypond

(require 'ob-lilypond)
(setq org-babel-lilypond-ly-command "lilypond.sh")

Org Evil

(use-package evil-org
  :demand
  :after org
  :init
  (add-hook 'org-mode-hook (lambda()
                             (define-key
                               evil-normal-state-local-map
                               (kbd "M-RET")
                               #'org-meta-return)))
  :hook (org-mode . (lambda () evil-org-mode)))

Org Modern

This just helps us make org look a bit more modern than just plain text

(use-package org-modern
  :demand
  :after org
  :config
  (setq org-pretty-entities nil)
  (global-org-modern-mode))

Org Download

(use-package org-download
  :demand
  :after org
  :config
  (setq org-download-screenshot-method "screencapture -i %s")
  (setq-default org-download-image-dir "~/roam/org/attachments/screenshots")
  :general
  (lc/leader-keys
    "s y" '(org-download-screenshot :wk "Capture Screenshot")
    "s c" '(org-download-clipboard :wk "Insert image from clipboard")
    "s d" '(org-download-image :wk "Download image")))

Org Tree Slide

(use-package org-tree-slide
  :config
  (global-set-key (kbd "<f8>") 'org-tree-slide-mode)
  (global-set-key (kbd "S-<f8>") 'org-tree-slide-skip-done-toggle)
  (define-key org-tree-slide-mode-map (kbd "<f9>")
    'org-tree-slide-move-previous-tree)
  (define-key org-tree-slide-mode-map (kbd "<f10>")
    'org-tree-slide-move-next-tree)
  (define-key org-tree-slide-mode-map (kbd "<f11>")
    'org-tree-slide-content)
  (setq org-tree-slide-skip-outline-level 4)
  (org-tree-slide-narrowing-control-profile)
  (setq org-tree-slide-skip-done nil)
  :demand)

Org Roam

The best of the best when it comes to taking comprehensive notes without getting lost in file structures.

(use-package org-roam
  :demand
  :after org
  :init
  (setq org-directory (file-truename "~/roam/org"))
  (setq org-roam-directory (file-truename "~/roam/org"))
  (setq lc-static-directory (file-truename "~/roam/static/generated"))
  (setq org-agenda-files (directory-files-recursively org-directory "\\.org$"))
  (setq org-roam-v2-ack t)
  (setq org-roam-completion-everywhere t)
  (setq org-roam-capture-templates
        '(("d" "default" plain "%?" :target
           (file+head "personal/%<%Y%m%d%H%M%S>-${slug}.org" "#+title: ${title}\n") :unnarrowed t)
          ("c" "contact" plain "%?" :target
           (file+head "contacts/%<%Y%m%d%H%M%S>-${slug}.org"  "#+title: ${title}\n") :unnarrowed t)
          ("w" "work" plain "%?" :target
           (file+head "work/%<%Y%m%d%H%M%S>-${slug}.org"  "#+title: ${title}\n") :unnarrowed t)))
  (setq org-roam-dailies-capture-templates
        '(("d" "default" plain
           "* %?"
           :target (file+head "personal/journal-%<%Y%m%d>.org" "#+title: Journal - %<%Y-%m-%d>\n") :unnarrowed t)
          ("w" "work" plain " * %?" :target
           (file+head "work/work-%<%Y%m%d>.org"  "#+title: Work Journal - %<%Y-%m-%d>\n") :unnarrowed t)))
  (setq org-roam-mode-sections
        (list #'org-roam-backlinks-section
              #'org-roam-reflinks-section
              #'org-roam-unlinked-references-section
              ))
  (add-to-list 'display-buffer-alist
             '("\\*org-roam\\#"
               (display-buffer-in-side-window)
               (side . right)
               (slot . 0)
               (window-width . 0.33)
               (window-parameters . ((no-other-window . t)
                                     (no-delete-other-windows . t)))))
  :general
  (lc/leader-keys
    "TAB n" '((lambda () (interactive) (persp-switch "notes")) :wk "notes")
    "n" '(:wk "roam")
    "n f" '(org-roam-node-find :wk "find node")
    "n i" '(org-roam-node-insert :wk "insert node")
    "n c" '(org-roam-capture :wk "capture")
    "n t" '(org-roam-tag-add :wk "add tag")
    "n r" '(org-roam-ref-add :wk "add ref")
    "n a" '(:wk "add alias")
    "n a a" '(org-roam-alias-add :wk "add alias")
    "n a r" '(org-roam-alias-remove :wk "add alias")
    "n g" '(org-roam-graph :wk "show roam graph")
    "n j" '(org-roam-dailies-capture-today :wk "capture today")
    "n J" '(org-roam-dailies-goto-today :wk "goto today")
    "n d" '(org-roam-dailies-goto-date :wk "goto date")
    "t b" '(org-roam-buffer-toggle :wk "roam buffer")
    )
  :config
  (org-roam-setup)
)
(require 'org-roam)
(defun lc/org-roam-filter-by-tag (tag-name)
  (lambda (node)
    (member tag-name (org-roam-node-tags node))))

(defun lc/org-roam-list-notes-by-tag (tag-name)
  (mapcar #'org-roam-node-file
          (seq-filter
           (lc/org-roam-filter-by-tag tag-name)
           (org-roam-node-list))))

(defun lc/org-roam-refresh-agenda-list ()
  (interactive)
  (setq org-agenda-files (append
                          (lc/org-roam-list-notes-by-tag "todo")
                          (lc/org-roam-list-notes-by-tag "project"))))

(lc/org-roam-refresh-agenda-list)

(nvmap :prefix "SPC"
  "o r" '(lc/org-roam-refresh-agenda-list :wk "refresh agenda"))

This next section handles cancelled or finished todos for us. Whenever a todo gets cancelled or finished, we make a copy of it into our daily notes. This way the node itself can later be cleaned up, but we keep a record of what was accomplished that day.

(defun lc/org-roam-copy-todo-to-today ()
  (interactive)
  (let ((org-refile-keep t)
        (org-roam-dailies-capture-templates
        '(("d" "default" plain
           "* %?"
           :if-new (file+head+olp "personal/%<%Y%m%d>.org" "#+title: Journal - %<%Y-%m-%d>\n" ("Tasks")))))
        (org-after-refile-insert-hook #'save-buffer)
        today-file
        pos)
    (save-window-excursion
      (org-roam-dailies--capture (current-time) t)
      (setq today-file (buffer-file-name))
      (setq pos (point)))

    (unless (equal (file-truename today-file)
                   (file-truename (buffer-file-name)))
      (org-refile nil nil (list "Tasks" today-file nil pos)))))

(add-to-list 'org-after-todo-state-change-hook
             (lambda ()
               (when (or
                      (equal org-state "DONE")
                      (equal org-state "CANCELED"))
                 (lc/org-roam-copy-todo-to-today))))

Org Roam Timestamps

(use-package org-roam-timestamps
  :after org-roam
  :config (org-roam-timestamps-mode))

Org Roam UI

Org Roam UI is a little add-on for org-roam that adds an interactive graph of all roam notes that is viewable in the browser.

(use-package websocket
  :after org-roam)
(use-package org-roam-ui
  :demand
  :config
  (setq org-roam-ui-sync-theme t
        org-roam-ui-follow t
        org-roam-ui-update-on-save t
        org-roam-ui-open-on-start t)
  :general
  (lc/leader-keys
    "n s" '(org-roam-ui-open :wk "show ui")))
(use-package ox-hugo
  :demand)
(defun clinton/org-roam--extract-note-body (file)
  (with-temp-buffer
    (insert-file-contents file)
    (org-mode)
    (car (org-element-map (org-element-parse-buffer) 'paragraph
             (lambda (paragraph)
               (let ((begin (plist-get (car (cdr paragraph)) :begin))
                     (end (plist-get (car (cdr paragraph)) :end)))
                 (buffer-substring begin end)))))))

(defun file-path-to-slug (path)
  (let* ((file-name (car (last (split-string path "--"))))
         (title (car (split-string file-name "\\."))))
    (replace-regexp-in-string (regexp-quote "_") "-" title nil 'literal)))

(defun file-path-to-md-file-name (path)
  (let ((file-name (car (last (split-string path "/")))))
    (concat (car (split-string file-name "\\.")) ".md")))

Projectile

(use-package projectile
  :demand
  :config
  (projectile-global-mode 1))

Completion

YaSnippet

(use-package yasnippet
  :demand
  :config
  (yas-global-mode 1))

Ivy

(use-package ivy
:defer 0.1
:diminish
:bind
(("C-c C-r" . ivy-resume)
 ("C-x B" . ivy-switch-buffer-other-window))
:custom
(setq ivy-count-format "(%d/%d) ")
(setq ivy-use-virtual-buffers t)
(setq enable-recursive-minibuffers t)
:config
(ivy-mode))

Corfu

(use-package corfu
  :demand
   :straight (corfu :files (:defaults "extensions/*")
                    :includes (corfu-popupinfo))
  :config
  (setq corfu-auto t)
  (setq corfu-cycle t)
  (setq corfu-popupinfo-delay t)
  :init
  (global-corfu-mode)
  (corfu-history-mode t))
(setq tab-always-indent 'complete)
(add-hook 'corfu-mode-hook #'corfu-popupinfo-mode)
  (use-package kind-icon
    :after corfu
    :config
    (add-to-list 'corfu-margin-formatters #'kind-icon-margin-formatter)
    :demand)
  ;; overriding image.el function image-type-available-p
(defun image-type-available-p (type)
  "Return t if image type TYPE is available.
Image types are symbols like `xbm' or `jpeg'."
  (if (eq 'svg type)
      nil
    (and (fboundp 'init-image-library)
         (init-image-library type))))
(use-package orderless
  :demand
  :init
  (setq completion-styles '(orderless basic)
    ))

Languages

Flycheck

(use-package flycheck :demand)

Language Server

(defun corfu-lsp-setup ()
  (setq-local completion-styles '(orderless)
              completion-category-defaults nil))
(use-package lsp-mode
  :demand
  :init
  :config
  (setq lsp-enable-symbol-highlighting t)
  :hook (
         (rust-mode . lsp)
         (lsp-mode . lsp-enable-which-key-integration))
  :commands lsp)

Language Server UI

(use-package markdown-mode :demand)
(setq lsp-completion-provider :none)
(add-hook 'lsp-mode-hook #'corfu-lsp-setup)
(use-package lsp-ui :demand :commands lsp-ui-mode
  :init
  (setq lsp-ui-sideline-enable t
        lsp-ui-sideline-show-diagnostics t
        lsp-ui-sideline-show-symbol t
        lsp-ui-sideline-show-hover t
        lsp-ui-sideline-show-actions t
        lsp-ui-sideline-delay 0
        lsp-ui-peek-enable t
        lsp-ui-doc-enhanced-markdown t)

  :bind
  :general
  (lc/leader-keys
    "t i" '(lsp-ui-imenu :wk "Show imenu")
    "t k" '(lsp-ui-imenu--kill :wk "Hide imenu")
    "c" '(:wk "Code actions")
    "c r" '(lsp-ui-peek-find-references :wk "Show references")
    "c j" '(lsp-ui-peek-find-definitions :wk "Find definitions")
    "c i"   '(lsp-ui-peek-find-implementation :wk "Find implementation"))
  :hook
  (lsp-mode . lsp-ui-mode)
  )
(use-package lsp-ivy :demand :commands lsp-ivy-workspace-symbol)

Tree-sittter

(use-package tree-sitter :demand)
(use-package tree-sitter-langs :demand)
(global-tree-sitter-mode)

C++

(use-package ccls
  :demand)

Rust

(use-package rustic
  :config
  (setq rustic-lsp-client 'eglot)
  :demand)

Haskell

(use-package haskell-mode
  :demand)
(add-hook 'haskell-mode-hook #'lsp)
(use-package lsp-haskell :demand)

Python

(use-package python-mode
  :demand)

Scala

(use-package scala-mode
  :demand
  :interpreter
    ("scala" . scala-mode))

Erlang

GraphQL

(use-package graphql-mode
  :demand)
(use-package ob-graphql
  :demand)

Nix

(use-package nix-mode
  :demand)

YAML

(use-package yaml-mode
  :demand)

magit

Best Git client, second best feature ofter org mode

(use-package magit
  :demand
  :general
  (lc/leader-keys
    "g" '(:wk "Magit")
    "g s" '(magit-status :wk "Status")
    "g l" '(magit-log-all :wk "Log")
    "g C" '(magit-checkout :wk "Checkout")
    "g c c" '(magit-commit :wk "Commit")
    "g c a" '(magit-commit-amend :wk "Amend")
    "g p" '(magit-push-to-remote :wk "Push")
  ))
(use-package diff-hl
  :demand)
(add-hook 'magit-pre-refresh-hook 'diff-hl-magit-pre-refresh)
(add-hook 'magit-post-refresh-hook 'diff-hl-magit-post-refresh)

Window Management

(winner-mode 1)
(nvmap :prefix "SPC"
       ;; Window splits
       "w"     '(:wk "Window Management")
       "w c"   '(evil-window-delete :which-key "Close window")
       "w n"   '(evil-window-new :which-key "New window")
       "w s"   '(evil-window-split :which-key "Horizontal split window")
       "w v"   '(evil-window-vsplit :which-key "Vertical split window")
       ;; Window motions
       "w h"   '(evil-window-left :which-key "Window left")
       "w j"   '(evil-window-down :which-key "Window down")
       "w k"   '(evil-window-up :which-key "Window up")
       "w l"   '(evil-window-right :which-key "Window right")
       "w <left>"   '(evil-window-left :which-key "Window left")
       "w <down>"   '(evil-window-down :which-key "Window down")
       "w <up>"   '(evil-window-up :which-key "Window up")
       "w <right>"   '(evil-window-right :which-key "Window right")
       "w w"   '(evil-window-next :which-key "Goto next window")
       ;; winner mode
       "w u"  '(winner-undo :which-key "Winner undo")
       "w r" '(winner-redo :which-key "Winner redo"))

Theme

We need a nice colorscheme. The Doom Emacs guys have a nice collection of themes, so let’s install them!

  (use-package doom-themes :demand)
  (use-package cyberpunk-theme :demand)
  (use-package solo-jazz-theme :demand)
  (use-package moe-theme :demand)
  (use-package exotica-theme :demand)
  (use-package flucui-themes
    :demand)
  (use-package hemisu-theme
    :demand)


  (use-package kaolin-themes
    :demand
    :config
    (kaolin-treemacs-theme))
  (use-package mindre-theme
    :straight (:host github :repo "erikbackman/mindre-theme")
    :demand)
  (use-package bespoke-themes
    :straight (:host github :repo "mclear-tools/bespoke-themes" :branch "main")
    :demand)
  (setq doom-themes-enable-bold t    ; if nil, bold is universally disabled
        doom-themes-enable-italic t) ; if nil, italics is universally disabled
  (load-theme 'moe-light t)

(defun lc/org-theme ()
    (interactive)
    (load-theme 'leuven t))
(defun lc/normal-theme ()
    (interactive)
    (load-theme 'kaolin-aurora))
(nvmap :states '(normal visual) :keymaps 'override :prefix "SPC"
       "a l"     '(lc/org-theme :which-key "Leuven Theme")
       "a n"     '(lc/normal-theme :which-key "Aurora Theme"))

Which Key

Which-key is a minor mode for Emacs that displays the key bindings following your currently entered incomplete command (a prefix) in a popup.

NOTE: Which-key has an annoying bug that in some fonts and font sizes, the bottom row in which key gets covered up by the modeline.

(use-package which-key
  :demand
  :init
  (setq which-key-side-window-location 'bottom
        which-key-sort-order #'which-key-key-order-alpha
        which-key-sort-uppercase-first nil
        which-key-add-column-padding 1
        which-key-max-display-columns nil
        which-key-min-display-lines 6
        which-key-side-window-slot -10
        which-key-side-window-max-height 0.25
        which-key-idle-delay 0.8
        which-key-max-description-length 25
        which-key-allow-imprecise-window-fit t
        which-key-separator "" ))
(which-key-mode)

Email

(push "~/.nix-profile/share/emacs/site-lisp/mu4e" load-path)
(require 'mu4e)
(setq mail-user-agentt 'mu4e-user-agent)
(setq mu4e-maildir-shortcuts
      '(
        (:maildir "/Gmail/INBOX" :key ?i))
      )
(setq mu4e-get-mail-command "offlineimap")
(setq mu4e-sent-messages-behavior 'delete)

(setq
 user-email-address "[email protected]"
 user-full-name "Simon Wollwage")

(setq message-kill-buffer-on-exit t)

(require 'smtpmail)
(setq message-send-mail-function 'smtpmail-send-it
      startttls-use-gnutls t
      smtpmail-startttls-credentials '(("smtp.gmail.com" 587 nil nil))
      smtpmail-auth-credentials '(("smtp.gmail.com" 587 "[email protected]" nil))
      smtpmail-default-smtp-server "smtp.gmail.com"
      smtpmail-smtp-server "smtp.gmail.com"
      smtpmail-smtp-service 587)

(nvmap :prefix "SPC"
  "t m" '(mu4e :wk "MU4E"))

EPub

(use-package nov
  :demand)

Utilities

Github

(use-package gh
  :straight (
             :repo "sigma/gh.el"
             :host github
             :branch "master")
  :demand)

Gist

(use-package gist
  :straight (
             :repo "defunkt/gist.el"
             :host github
             :branch "master")
  :demand)

Hledger

(use-package hledger-mode
  :mode ("\\.journal\\'" "\\.hledger\\'")
  :commands hledger-enable-reporting
  :demand
  :bind (:map hledger-mode-map
              ("TAB" . completion-at-point))
  :preface
  (defun popup-balance-at-point ()
    "Show balance for account at point in a popup."
    (interactive)
    (if-let ((account (thing-at-point 'hledger-account)))
        (message (hledger-shell-command-to-string (format " balance -N %s "
                                                          account)))
      (message "No account at point")))

  :config
  :config
  (add-hook 'hledger-view-mode-hook #'hl-line-mode)
  (add-hook 'hledger-view-mode-hook #'center-text-for-reading)

  (add-hook 'hledger-view-mode-hook
            (lambda ()
              (run-with-timer 1
                              nil
                              (lambda ()
                                (when (equal hledger-last-run-command
                                             "balancesheet")
                                  ;; highlight frequently changing accounts
                                  (highlight-regexp "^.*\\(savings\\|cash\\).*$")
                                  (highlight-regexp "^.*credit-card.*$"
                                                    'hledger-warning-face))))))

  (add-hook 'hledger-mode-hook
            (lambda ()
              (make-local-variable 'company-backends)
              (add-to-list 'company-backends 'hledger-company)))
  
  (setq hledger-input-buffer-height 20)
  (add-hook 'hledger-input-post-commit-hook #'hledger-show-new-balances)
  (add-hook 'hledger-input-mode-hook #'auto-fill-mode)
  (add-hook 'hledger-input-mode-hook
            (lambda ()
              (make-local-variable 'company-idle-delay)
              (setq-local company-idle-delay 0.1))))
(require 'hledger-input)

Snippets

Emacs Lisp

# -*- mode: snippet -*-
# contributor: Daniel Hitzel
# name: use-package
# key: up
# --
(use-package ${1:package-name}
:demand)

Org-mode

# -*- mode: snippet -*-
# name: src
# key: <src
# --
  $0
#+end_src
# -*- mode: snippet -*-
# name: snippet
# key: <sn
# --
#+begin_src ${1:lang} :mkdirp yes :tangle ~/.emacs.d/snippets/${2:mode}/${3:name}
$0
#+end_src
# -*- mode: snippet -*-
# name: emacs-lisp
# key: <em
# --
$0
#+end_src
# -*- mode: snippet -*-
# name: shell
# key: <sh
# --
#+begin_src sh :results ${1:result}
$0
#+end_src
# -*- mode: snippet -*-
# name: ssh
# key: <ssh
# --
#+begin_src sh :results ${1:result} :dir /ssh:${2:server}:${3:path}
$0
#+end_src
# -*- mode: snippet -*-
# name: docker
# key: <docker
# --
#+begin_src sh :results ${1:result} :dir /docker:${2:container}:${3:path}
$0
#+end_src
# -*- mode: snippet -*-
# name: rust
# key: <rust
# --
#+begin_src rust :results ${1:result} :tangle ${2:no}
$0
#+end_src

Rust

# -*- mode: snippet -*-
# name: impl FromStr for Type { fn from_str(...) }
# key: fromstr
# --
impl FromStr for ${1:Type} {
    type Err = ${2:Error};

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        Ok(Self{})
    }
}
# -*- mode: snippet -*-
# name: impl Display for Type { fn fmt (...) }
# key: display
# --
impl Display for ${1:Type} {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "$0")
    }
}

File local variables

;; Local Variables: ;; eval: (add-hook ‘after-save-hook (lambda ()(if (y-or-n-p “Reload?”)(load-file user-init-file))) nil t) ;; eval: (add-hook ‘after-save-hook (lambda ()(if (y-or-n-p “Tangle?”)(org-babel-tangle))) nil t) ;; End:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment