About Projects GitLab GitHub Page-Source

Introduction

Emacs is not just a text editor. It provides a full working environment to manipulate text files.

About this Configuration

Make this file run (slightly) faster with lexical binding (see this blog post for more info).

;;; config.el -*- lexical-binding: t; -*-
;;; In case you run in trouble:
;;(toggle-debug-on-error)
;; This Configuration File is managed by ~/Emacs.org. See additional comments there.

About Me

gpg --list-secret-keys | head -n4 | tail -n1 | cut -d' ' -f7
gpg --list-secret-keys | head -n5 | tail -n1 | cut -d'<' -f2 | cut -d'>' -f1
(setq user-full-name "Jonathan Pieper"
      user-mail-address "nil"
      calendar-longitude +8.8   ; 8.8  East
      calendar-latitude  +50.1  ; 50.1 Nord
      epg-user-id "nil")

Initialization (init.el)

Docstring

;;; init.el -*- lexical-binding: t; -*-

;; This file controls what Doom modules are enabled and what order they load
;; in. Remember to run 'doom sync' after modifying it!

;; NOTE Press 'SPC h d h' (or 'C-h d h' for non-vim users) to access Doom's
;;      documentation. There you'll find a "Module Index" link where you'll find
;;      a comprehensive list of Doom's modules and what flags they support.

;; NOTE Move your cursor over a module's name (or its flags) and press 'K' (or
;;      'C-c c k' for non-vim users) to view its documentation. This works on
;;      flags as well (those symbols that start with a plus).
;;
;;      Alternatively, press 'gd' (or 'C-c c d') on a module to browse its
;;      directory (for easy access to its source code).

Enable Features

Just comment/uncomment some lines to disable/enable features.

(doom! :input
       ;;chinese
       ;;japanese
       ;;layout            ; auie,ctsrnm is the superior home row

       :completion
       (company
       ;; +childframe
        )           ; the ultimate code completion backend
       ;; helm              ; the *other* search engine for love and life
       ;; ido               ; the other *other* search engine...
       ;; (ivy
        ;; +fuzzy              ; Enables fuzzy completion for Ivy searches
        ;; +prescient            ; Enables prescient filtering and sorting for Ivy searches.
        ;; +childframe         ; display in a floating window
        ;; +icons)               ; a search engine for love and life
       (vertico +icons)           ; the search engine of the future

       :ui
       deft               ; notational velocity for Emacs
       doom               ; what makes DOOM look the way it does
       doom-dashboard     ; a nifty splash screen for Emacs
       ;;doom-quit        ; DOOM quit-message prompts when you quit Emacs
       (emoji +unicode)   ; 🙂
       hl-todo            ; highlight TODO/FIXME/NOTE/DEPRECATED/HACK/REVIEW
       hydra
       indent-guides      ; highlighted indent columns
       (ligatures +extra) ; ligatures and symbols to make your code pretty again
       ;;minimap          ; show a map of the code on the side
       modeline           ; snazzy, Atom-inspired modeline, plus API
       nav-flash          ; blink cursor line after big motions
       ;;neotree          ; a project drawer, like NERDTree for vim
       ophints            ; highlight the region an operation acts on
       (popup +defaults)  ; tame sudden yet inevitable temporary windows
       ;;tabs             ; a tab bar for Emacs
       treemacs           ; a project drawer, like neotree but cooler
       unicode          ; extended unicode support for various languages
       vc-gutter          ; vcs diff in the fringe
       vi-tilde-fringe    ; fringe tildes to mark beyond EOB
       window-select      ; visually switch windows
       workspaces         ; tab emulation, persistence & separate workspaces
       zen                ; distraction-free coding or writing

       :editor
       (evil +everywhere); come to the dark side, we have cookies
       file-templates    ; auto-snippets for empty files
       fold              ; (nigh) universal code folding
       (format)          ; automated prettiness
       ;;god               ; run Emacs commands without modifier keys
       ;;lispy             ; vim for lisp, for people who don't like vim
       ;;multiple-cursors  ; editing in many places at once
       ;;objed             ; text object editing for the innocent
       ;;parinfer          ; turn lisp into python, sort of
       ;;rotate-text       ; cycle region at point between text candidates
       snippets            ; my elves. They type so I don't have to
       ;;word-wrap         ; soft wrapping with language-aware indent

       :emacs
       (dired +icons)    ; making dired pretty [functional]
       electric          ; smarter, keyword-based electric-indent
       (ibuffer +icons)  ; interactive buffer management
       (undo +tree)      ; persistent, smarter undo for your inevitable mistakes
       ;; vc                ; version-control and Emacs, sitting in a tree

       :term
       eshell            ; the elisp shell that works everywhere
       ;;shell             ; simple shell REPL for Emacs
       ;;term              ; basic terminal emulator for Emacs
       vterm             ; the best terminal emulation in Emacs

       :checkers
       syntax              ; tasing you for every semicolon you forget
       (spell +flyspell) ; tasing you for misspelling mispelling
       grammar           ; tasing grammar mistake every you make

       :tools
       ;;ansible
       debugger          ; FIXME stepping through code, to help you add bugs
       direnv
       ;; docker
       ;;editorconfig      ; let someone else argue about tabs vs spaces
       ein               ; tame Jupyter notebooks with emacs
       (eval +overlay)     ; run code, run (also, repls)
       ;;gist              ; interacting with github gists
       (lookup              ; navigate your code and its documentation
        +dictionary         ; dictionary/thesaurus is nice
        +offline            ; download with wordnut and synosaurus
        +docsets)           ; ...or in Dash docsets locally
       lsp               ; M-x vscode
       (magit)           ; a git porcelain for Emacs
        ;; +forge)          ; interface with git forges
       make              ; run make tasks from Emacs
       (pass +auth)      ; password manager for nerds
       pdf               ; pdf enhancements
       ;;prodigy           ; FIXME managing external services & code builders
       ;;rgb               ; creating color strings
       ;;taskrunner        ; taskrunner for all your projects
       ;;terraform         ; infrastructure as code
       tmux              ; an API for interacting with tmux
       upload            ; map local to remote projects via ssh/ftp

       :os
       (:if IS-MAC macos)  ; improve compatibility with macOS
       tty               ; improve the terminal Emacs experience

       :lang
       ;;agda              ; types of types of types of types...
       ;;beancount         ; mind the GAAP
       ;;cc                ; C > C++ == 1
       ;;clojure           ; java with a lisp
       ;;common-lisp       ; if you've seen one lisp, you've seen them all
       ;;coq               ; proofs-as-programs
       ;;crystal           ; ruby at the speed of c
       ;;csharp            ; unity, .NET, and mono shenanigans
       data              ; config/data formats
       ;;(dart +flutter)   ; paint ui and not much else
       ;;elixir            ; erlang done right
       ;;elm               ; care for a cup of TEA?
       emacs-lisp        ; drown in parentheses
       ;;erlang            ; an elegant language for a more civilized age
       ;;ess               ; emacs speaks statistics
       ;;factor
       ;;faust             ; dsp, but you get to keep your soul
       ;;fsharp            ; ML stands for Microsoft's Language
       ;;fstar             ; (dependent) types and (monadic) effects and Z3
       ;;gdscript          ; the language you waited for
       ;;(go +lsp)         ; the hipster dialect
       (haskell +dante)  ; a language that's lazier than I am
       ;;hy                ; readability of scheme w/ speed of python
       ;;idris             ; a language you can depend on
       json              ; At least it ain't XML
       ;;(java +meghanada) ; the poster child for carpal tunnel syndrome
       javascript        ; all(hope(abandon(ye(who(enter(here))))))
       ;;julia             ; a better, faster MATLAB
       ;;kotlin            ; a better, slicker Java(Script)
       (latex             ; writing papers in Emacs has never been so fun
        +latexmk                    ; what else would you use?
        +cdlatex                    ; quick maths symbols
        +lsp                        ; language server
        +fold)                      ; fold the clutter away nicities
       ;;lean              ; for folks with too much to prove
       ledger            ; be audit you can be
       lua               ; one-based indices? one-based indices
       markdown          ; writing docs for people to ignore
       nim               ; python + lisp at the speed of c
       ;;nix               ; I hereby declare "nix geht mehr!"
       ;;ocaml             ; an objective camel
       (org               ; organize your plain life in plain text
        ;;+pretty                     ; yessss my pretties! (nice unicode symbols)
        +dragndrop                  ; drag & drop files/images into org buffers
        ;;+hugo                     ; use Emacs for hugo blogging
        +noter                      ; enhanced PDF notetaking
        +jupyter                    ; ipython/jupyter support for babel
        +ipython                    ; ipython for babel
        +pandoc                     ; export-with-pandoc support
        +gnuplot                    ; who doesn't like pretty pictures
        ;;+pomodoro                 ; be fruitful with the tomato technique
        +present                    ; using org-mode for presentations
        +roam2)                     ; wander around notes
       ;;php               ; perl's insecure younger brother
       plantuml          ; diagrams for confusing people more
       ;;purescript        ; javascript, but functional
       (python            ; beautiful is better than ugly
        +lsp)             ; language server protocol
        ;; +pyright           ;
        ;; +conda)            ; Anaconda environment / package manager
       qt                ; the 'cutest' gui framework ever
       ;;racket            ; a DSL for DSLs
       ;;raku              ; the artist formerly known as perl6
       ;;rest              ; Emacs as a REST client
       rst               ; ReST in peace
       (ruby +rails)     ; 1.step {|i| p "Ruby is #{i.even? ? 'love' : 'life'}"}
       rust              ; Fe2O3.unwrap().unwrap().unwrap().unwrap()
       ;;scala             ; java, but good
       (scheme +guile)   ; a fully conniving family of lisps
       sh                ; she sells {ba,z,fi}sh shells on the C xor
       ;;sml
       ;;solidity          ; do you need a blockchain? No.
       ;;swift             ; who asked for emoji variables?
       ;;terra             ; Earth and Moon in alignment for performance.
       web               ; the tubes
       yaml              ; JSON, but readable
       ;;zig               ; C, but simpler

       :email
       ;;(mu4e +org) ;; +gmail
       ;;notmuch
       ;;(wanderlust +gmail)

       :app
       calendar
       emms                ; Web Browser
       everywhere        ; *leave* Emacs!? You must be joking
       irc               ; how neckbeards socialize
       (rss +org)        ; emacs as an RSS reader
       ;;twitter           ; twitter client https://twitter.com/vnought

       :config
       ;;literate
       (default +bindings +smartparens))

Package Installation (packages.el)

Docstring

;; -*- no-byte-compile: t; -*-
;;; $DOOMDIR/packages.el

;; To install a package with Doom you must declare them here and run 'doom sync'
;; on the command line, then restart Emacs for the changes to take effect -- or
;; use 'M-x doom/reload'.


;; To install SOME-PACKAGE from MELPA, ELPA or emacsmirror:
;(package! some-package)

;; To install a package directly from a remote git repo, you must specify a
;; `:recipe'. You'll find documentation on what `:recipe' accepts here:
;; https://github.com/raxod502/straight.el#the-recipe-format
;(package! another-package
;  :recipe (:host github :repo "username/repo"))

;; If the package you are trying to install does not contain a PACKAGENAME.el
;; file, or is located in a subdirectory of the repo, you'll need to specify
;; `:files' in the `:recipe':
;(package! this-package
;  :recipe (:host github :repo "username/repo"
;           :files ("some-file.el" "src/lisp/*.el")))

;; If you'd like to disable a package included with Doom, you can do so here
;; with the `:disable' property:
;(package! builtin-package :disable t)

;; You can override the recipe of a built in package without having to specify
;; all the properties for `:recipe'. These will inherit the rest of its recipe
;; from Doom or MELPA/ELPA/Emacsmirror:
;(package! builtin-package :recipe (:nonrecursive t))
;(package! builtin-package-2 :recipe (:repo "myfork/package"))

;; Specify a `:branch' to install a package from a particular branch or tag.
;; This is required for some packages whose default branch isn't 'master' (which
;; our package manager can't deal with; see raxod502/straight.el#279)
;(package! builtin-package :recipe (:branch "develop"))

;; Use `:pin' to specify a particular commit to install.
;(package! builtin-package :pin "1a2b3c4d5e")


;; Doom's packages are pinned to a specific commit and updated from release to
;; release. The `unpin!' macro allows you to unpin single packages...
;(unpin! pinned-package)
;; ...or multiple packages
;(unpin! pinned-package another-pinned-package)
;; ...Or *all* packages (NOT RECOMMENDED; will likely break things)
;(unpin! t)

Load Packages

;; Use latest versions!
(unpin! org-roam org)
(unpin! bibtex-completion helm-bibtex ivy-bibtex)

;; (package! f.el :pin "3737e7d4ab2775391e5173da1d593dc9e7355d98") ; Important for older Emacs 29.0.50 versions
(package! all-the-icons)

;; Org Enhancements
(package! evil-tutor)           ; Tutor to get familiar with doom emacs (and evil vi keybindings).
(package! org-roam)             ; Extended org-mode for Zettelkasten principle.
(package! org-logseq
  :recipe (:host github
           :repo "llcc/org-logseq"
           :files ("*")))
(package! org-ref)              ; References and citations
(package! org-super-agenda)
(package! org-appear)           ; Display markup symbols (*=~ etc.) on cursor-over
(package! org-alert)            ; Enable org-mode notifications.
;; (package! org-tree-slide)       ; Enable org-mode presentations.
(package! org-present)
(package! org-superstar)           ; Alternative for org-bullets and org-superstar.
(package! org-pdfview)          ; Allows to annotate pdf in org-mode.
(package! org-download)
(package! org-journal)
(package! org-sidebar)
(package! org-protocol-capture-html
  :recipe (:host github
           :repo "alphapapa/org-protocol-capture-html"
           :files ("org-protocol-capture-html.el")))
(package! org-special-block-extras
  :recipe (:host github
           :repo "alhassy/org-special-block-extras"))
(package! helm-org-ql
  :recipe (:host github
           :repo "alphapapa/org-ql"
           :files ("helm-org-ql.el")))
(package! org-ql
  :recipe (:host github
           :repo "alphapapa/org-ql"
           :files (:defaults (:exclude "helm-org-ql.el"))))

;; Org Roam
(package! org-transclusion)
(package! vulpea)
(package! delve
  :recipe (:repo "publicimageltd/delve"
           :host github))

;; Bibliography
(package! org-roam-bibtex
  :recipe (:host github :repo "org-roam/org-roam-bibtex"))
(package! helm-bibtex)
(package! citar)

;; Org Roam UI (frontend for exploring and interacting org-roam)
(package! websocket)
(package! org-roam-ui
  :recipe (:host github
           :repo "org-roam/org-roam-ui"
           :files ("*.el" "out")))

;; PlantUML
(package! ob-napkin)            ; PlantUML in Org Babel
(package! plantuml-mode)        ; PlantUML Diagrams

;; Org Exports (ox-*)
(package! ox-twbs)      ; HTML Twitter Bootstrap
(package! ox-rst)       ; ReStructured Text (ReST, RST)

;; Support for other File Types
(package! pdf-tools)            ; Additional pdf tools.
(package! nov)                  ; View epub files.

;; (package! telega
;;   :recipe (:host github
;;            :repo "zevlg/telega.el"
;;            :branch "master"
;;            :files (:defaults "contrib" "etc" "server" "Makefile")))

(package! emacs-bitwarden       ; Password Manager
  :recipe (:host nil
           :build t
           :type git
           :repo "https://labs.phundrak.com/phundrak/bitwarden.el"
           ;; :files ("bitwarden.el")
           ))

;; Visual Enhancements
(package! rainbow-mode)         ; Converts #0000FF and (nested (parethesis)) into colored cues.
(package! emojify)              ; Convert ☺ into emoji's.
(package! ef-themes)

;; Functional Enhancements
(package! popper)
(package! embark)
(package! helm-ag)              ; Ack and the_silver_searcher support

;; Other Software Integrations
(package! guix
  :recipe (:host nil
           :repo "https://git.savannah.gnu.org/git/guix/emacs-guix.git"))
(package! dmenu)                ; Dmenu Plugin.
(package! tldr)                 ; Too long; Didn't read (short man pages).
;; (package! forge)                ; Additional git features (linking issues from github etc.)
(package! eshell-git-prompt)
(package! company-ledger)
(package! diminish)
(package! beacon)               ; Highlight Cursor on big change

;; Feed Reader
(package! elfeed)
(package! elfeed-score)

;; Calendar
(package! calfw)
(package! calfw-org)
(package! german-holidays
  :recipe (:host nil
           :repo "https://gitlab.ody5.eu/ody55eus/german-holidays.git"
           :files ("german-holidays.el")))

;; Dictionaries
(package! synosaurus)           ; Thesaurus synonyms
(package! powerthesaurus)
;;(package! wordnut)
;;(package! ement.el)

;; Language Server
(package! apheleia)    ; Code Formatter
(package! lsp-mode)
(package! lsp-ui)
(package! lsp-treemacs)
;;(package! lsp-ivy)
(package! lsp-pyright)          ; Python language server
(package! lsp-latex)
(package! dap-mode)             ; Debugging Functions
(package! company-box)          ; Auto-Completion
(package! pomm
  :recipe (:host github
           :repo "SqrtMinusOne/pomm.el"))

(package! beancount-mode
  :recipe (:host github
           :repo "beancount/beancount-mode"
           :files ("beancount.el")))

;; (package! mu4e-dashboard
;;   :recipe (:host github
;;            :repo "rougier/mu4e-dashboard"))

(package! xkcd)

;; Packages to share my keybindings when streaming
(package! keycast
  :recipe (:host github
           :repo "tarsius/keycast"))

(package! emacs-rotate
  :recipe (:host github
           :repo "daichirata/emacs-rotate"))

MacOS Only Packages

  • Spotlight uses MacOS system’s search engine to find files.
;; MacOS Only
(package! spotlight)

Emacs Startup

Improve Startup Performance

  • Garbage Collection
    ;; The default is 800 kilobytes.  Measured in bytes.
    (setq gc-cons-threshold (* 50 1000 1000))
    
  • Startup Time
    (defun jp/display-startup-time ()
      (message "Emacs loaded in %s with %d garbage collections."
               (format "%.2f seconds"
                       (float-time
                        (time-subtract after-init-time before-init-time)))
               gcs-done))
    
    (add-hook 'emacs-startup-hook #'jp/display-startup-time)
    

Start Emacs as Server!

(require 'server)
(if (not (server-running-p))
    (server-start))  ; Start Emacs as Server!

Default Variables

Inspired by tecosaur and angrybacon/dotemacs.org.

(setq-default
 delete-by-moving-to-trash t        ; Delete files to trash
 mouse-yank-at-point t              ; Yank at point rather than pointer
 window-combination-resize t)       ; take new window space from all other windows (not just current)
(setq tab-width 2                   ; Smaller width for tab characters
      undo-limit 80000000           ; Raise undo-limit to 80Mb
      indent-tabs-mode nil          ; Do not use tabs to indent lines
      scroll-margin 2               ; Add a margin when scrolling vertically
      x-stretch-cursor t)           ; Stretch cursor to the glyph width
(set-default-coding-systems 'utf-8) ; Default to utf-8 encoding

;;;; backups
(setq backup-by-copying t
      version-control t
      vc-make-backup-files t
      delete-old-versions 0
      auto-save-include-big-deletions t
      backup-directory-alist `((".*" . ,(concat (or (getenv "XDG_CACHE_HOME") doom-cache-dir) "/emacs/backups")))
      auto-save-file-name-transforms `((".*" ,(concat (or (getenv "XDG_CACHE_HOME") doom-cache-dir) "/emacs/autosaves") t)))


;; World Clock
(setq world-clock-list '(("UTC" "Universal")
                         ("America/Los_Angeles" "Seattle")
                         ("America/Chicago" "Chicago")
                         ("America/New_York" "New York")
                         ("Europe/London" "London")
                         ("Europe/Paris" "Paris")
                         ("Europe/Athens" "Athen")
                         ("Asia/Dubai" "Dubai")
                         ("Asia/Calcutta" "Calcutta")
                         ("Asia/Bangkok" "Bangkok")
                         ("Asia/Singapore" "Singapur")
                         ("Australia/Perth" "Perth")
                         ("Asia/Tokyo" "Tokyo")
                         ("Australia/Sydney" "Sydney")))

(defvar jp/guix? (if (getenv "GUIX_LOCPATH") t nil)) ; Are we running GNU/GUIX?

Frame Transparency

;; Frame Transparency
(defun jp/toggle-window-transparency ()
  "Toggle transparency."
  (interactive)
  (let ((alpha-transparency 85))
    (if (eq (frame-parameter nil 'alpha-background) alpha-transparency)
        (set-frame-parameter nil 'alpha-background 100)
      (set-frame-parameter nil 'alpha-background alpha-transparency))))
(add-hook 'emacs-startup-hook #'jp/toggle-window-transparency)

Workflow

Org Mode Workflow

See my Org-Mode Workflow for more details.

Additional Configuration Files

(if (file-directory-p (file-truename "~/.config/doom"))
  (add-to-list 'load-path (file-truename "~/.config/doom"))
  (add-to-list 'load-path (file-truename "~/.doom.d")))
(require 'org-workflow)
(setq org-logseq-dir "~/ZK/logseq")

UI Configuration

Keybindings

  • Basic Keybindings for leader (SPC-<Key>)
    (map! :leader
          (:prefix ("b" . "buffer")
           :desc "Consult buffer" :n "o" #'consult-buffer
           :desc "Consult buffer other window" :n "j" #'consult-buffer-other-window
           :desc "List bookmarks" "L" #'list-bookmarks
           :desc "Save current bookmarks to bookmark file" "w" #'bookmark-save)
          ;; (:prefix-map ("c" . "code"))
          ;; (:prefix-map ("d" . "dired"))
          ;; (:prefix-map ("f" . "file"))
          ;; (:prefix-map ("g" . "git"))
          ;; (:prefix-map ("h" . "help"))
          (:prefix ("i" . "insert")
           :desc "all-the-icons-insert" "a" #'all-the-icons-insert
           :desc "helm-ucs" "8" #'helm-ucs
           )
          ;; (:prefix-map ("m" . "org manage")
          ;;  (:prefix ("a" . "attatch"))
          ;;  (:prefix ("b" . "table"))
          ;;  (:prefix ("c" . "clock"))
          ;;  (:prefix ("d" . "date"))
          ;;  )
          (:prefix ("o" . "open")
           :desc "spotlight" "s" #'spotlight
           (:prefix ("j" . "jp")
            :desc "jp/org-roam-agenda" "a" #'jp/org-roam-agenda
            :desc "jp/enable-bitwarden" "b" #'jp/enable-bitwarden
            :desc "jp/go-to-inbox" "i" #'jp/go-to-inbox
            :desc "jp/go-to-projects" "p" #'jp/go-to-projects
            (:prefix ("r" . "roam")
             :desc "jp/org-roam-agenda" "a" #'jp/org-roam-agenda
             :desc "jp/org-roam-ignore-literature" "L" #'jp/org-roam-ignore-literature
             :desc "jp/org-roam-select-literature" "l" #'jp/org-roam-select-literature
             :desc "jp/org-roam-ignore-other" "O" #'jp/org-roam-ignore-other
             :desc "jp/org-roam-select-other" "o" #'jp/org-roam-select-other
             :desc "jp/org-roam-ignore-projects" "P" #'jp/org-roam-ignore-projects
             :desc "jp/org-roam-select-projects" "p" #'jp/org-roam-select-projects
             (:prefix ("r" . "review")
              :desc "jp/daily-review" "d" #'jp/daily-review
              :desc "jp/monthly-review" "m" #'jp/monthly-review
              :desc "jp/weekly-review" "w" #'jp/weekly-review
              )
             :desc "jp/org-roam-ignore-pc" "C" #'jp/org-roam-ignore-pc
             :desc "jp/org-roam-select-pc" "c" #'jp/org-roam-select-pc
             )
            )
           )
          ;; (:prefix-map ("p" . "projectile"))
          ;; (:prefix-map ("q" . "quit"))
          (:prefix ("s" . "search")
           :desc "counsel ag" "a" #'counsel-ag
           :desc "helm ag" "A" #'helm-ag
           :desc "Search/Insert BibTeX Cite" "c" #'org-ref-cite-insert-helm
           :desc "Consult Ripgrep" :n "R" #'consult-ripgrep
           (:prefix ("g" . "GNU/Guix")
            :desc "All Packages" "ap" #'guix-all-packages
            :desc "All Services" "as" #'guix-all-services
            :desc "Guix Command" "c" #'guix-command
            :desc "Guix (Popup)" "g" #'guix-popup
            :desc "Lint" "L" #'guix-lint
            :desc "Find License Definition" "l" #'guix-find-license-definition
            :desc "Find Package Definition" "p" #'guix-find-package-definition
            :desc "Find Service Definition" "s" #'guix-find-service-definition
            )
           )
          (:prefix ("t" . "toggle")
           :desc "Toggle alpha/transparency" "a" #'jp/toggle-window-transparency
           :desc "Toggle global debug on error" "d" #'toggle-debug-on-error
           :desc "Org Present" "p"  #'org-present
           :desc "Toggle line highlight local" "h" #'hl-line-mode
           :desc "Toggle line highlight globally" "H" #'global-hl-line-mode
           :desc "Toggle KeyCast Mode" "k" #'keycast-mode
           :desc "Toggle Menu Bar" "m" #'menu-bar-mode
           :desc "Toggle writegood mode" "S" #'writegood-mode
           :desc "Toggle truncate lines" "t" #'toggle-truncate-lines
           :desc "Toggle highlight TODOs" "T" #'hl-todo-mode
           :desc "Toggle visual fill column" "v" #'visual-fill-column-mode
           (:prefix ("SPC" . "Whitespaces")
            :desc "Toggle local whitespace option" "l" #'whitespace-toggle-options
            :desc "Toggle global whitespace option" "g" #'global-whitespace-toggle-options
            :desc "Toggle local whitespace mode" "t" #'whitespace-mode
            :desc "Toggle global whitespace mode" "w" #'global-whitespace-mode
            )
           )
          (:prefix ("w" . "window")
           :desc "hydra" "e" #'jp/hydra/windows/body
           :desc "evil-window-left" :n "<left>" #'evil-window-left
           :desc "evil-window-right" :n "<right>" #'evil-window-right
           :desc "evil-window-up" :n "<up>" #'evil-window-up
           :desc "evil-window-down" :n "<down>" #'evil-window-down
           )
          (:prefix ("n" . "notes")
                   (:prefix ("r" . "roam")
                    :desc "Insert BibTeX Note Link" "b" #'orb-insert-link
                    :desc "BibTeX Note Actions" "B" #'orb-note-actions
                    :desc "Complete org-roam " :n "c" #'org-roam-complete-at-point
                    :desc "Delve" :n "D" #'delve
                    :desc "New Daily Node (today)" :n "t" #'org-roam-dailies-capture-today
                    :desc "Find org-roam Node" :n "F" #'org-roam-node-find
                    :desc "Find no priv Node" :n "f" #'jp/org-roam-ignore-priv
                    :desc "Find no acg Node" :n "q" #'jp/org-roam-ignore-acg
                    :desc "Insert org-roam Node" :n "i" #'org-roam-node-insert
                    :desc "Capture new org-roam Node" :n "n" #'org-roam-capture
                    :desc "Org Roam UI" :n "u" #'org-roam-ui-open
                    :desc "Jump to Date" :n "j" #'jp/org-roam-jump-menu/body
                    )
                   )
          ;; (:prefix-map ("TAB" . "workspace"))
          )
    
    
  • Evaluate Lisp Expressions (SPC-e)

    Original by Derek Taylor (see dwt1/dotfiles)

    Changing some keybindings from their defaults to better fit with Doom Emacs, and to avoid conflicts with my window managers which sometimes use the control key in their keybindings. By default, Doom Emacs does not use SPC-e for anything, so I choose to use the format SPC-e plus key for these (I also use SPC-e for eww keybindings).

    COMMAND DESCRIPTION KEYBINDING
    eval-buffer Evaluate elisp in buffer SPC e b
    eval-defun Evaluate the defun containing or after point SPC e d
    eval-expression Evaluate an elisp expression SPC e e
    eval-last-sexp Evaluate elisp expression before point SPC e l
    eval-region Evaluate elisp in region SPC e r
    (map! :leader
          (:prefix ("e". "evaluate/EWW")
           :desc "Evaluate elisp in buffer" :n "b" #'eval-buffer
           :desc "Evaluate defun" :n "d" #'eval-defun
           :desc "Evaluate elisp expression" :n "e" #'eval-expression
           :desc "Evaluate last sexpression" :n "l" #'eval-last-sexp
           :desc "Evaluate elisp in region" :n "r" #'eval-region))
    
    
  • TODO Lookup (SPC-l)
    (map! :leader
          (:prefix ("l" . "lookup")
           (:prefix ("p" . "passwords")
            :desc "list-all" "a" #'bitwarden-list-all
            :desc "jp/enable-bitwarden" "e" #'jp/enable-bitwarden
            :desc "getpass" "g" #'bitwarden-getpass
            :desc "login" "l" #'bitwarden-login
            :desc "unlock" "u" #'bitwarden-unlock
            :desc "remove from kill-ring" "x" #'embark-kill-ring-remove
                     )
           :desc "helm-M-x" "c" #'helm-M-x
           :desc "helm-bibtex" "b" #'helm-bibtex
           :desc "counsel-fonts" "f" #'counsel-fonts
           :desc "helm-occur" "o" #'helm-occur
           :desc "helm-imenu" "i" #'helm-imenu
           :desc "helm-imenu-in-all-buffers" "I" #'helm-imenu-in-all-buffers
           :desc "helm-regexp" "r" #'helm-regexp
           :desc "helm-ucs" "S" #'helm-ucs
           :desc "helm-top" "T" #'helm-top
           :desc "helm-tldr" "t" #'helm-tldr
           :desc "helm-man-woman" "m" #'helm-man-woman
           )
          )
    
    
  • TODO Jump (SPC-j)
    (map! :leader
          (:prefix ("j" . "jump")
           :desc "avy-goto-char" "c" #'avy-goto-char
           :desc "avy-goto-char-timer" "o" #'avy-goto-char-timer
           :desc "avy-goto-char-2" "O" #'avy-goto-char-2
           :desc "avy-imenu" "I" #'avy-imenu
           :desc "evil-avy-goto-line" "l" #'evil-avy-goto-line
           :desc "helm-mark-ring" "m" #'helm-mark-ring
           :desc "pomm" "p" #'pomm
           :desc "evil-avy-goto-word-0" "w" #'evil-avy-goto-word-0
           :desc "evil-avy-goto-subword-0" "W" #'evil-avy-goto-subword-0
           )
          )
    
  • Special Hydra Bindings
    (define-key bibtex-mode-map (kbd "M-b") 'org-ref-bibtex-hydra/body)
    (define-key org-mode-map (kbd "C-c ]") 'org-ref-insert-link-hydra/body)
    
  • Embark (C-:)
    (require 'embark)
    (global-set-key (kbd "C-@") 'embark-act)
    
    (eval-when-compile
      (defmacro my/embark-ace-action (fn)
        `(defun ,(intern (concat "my/embark-ace-" (symbol-name fn))) ()
           (interactive)
           (with-demoted-errors "%s"
             (require 'ace-window)
             (aw-switch-to-window (aw-select nil))
             (call-interactively (symbol-function ',fn)))))
    
      (defmacro my/embark-split-action (fn split-type)
        `(defun ,(intern (concat "my/embark-"
                                 (symbol-name fn)
                                 "-"
                                 (car (last  (split-string
                                              (symbol-name split-type) "-"))))) ()
           (interactive)
           (funcall #',split-type)
           (call-interactively #',fn))))
    
    (define-key embark-file-map     (kbd "o") (my/embark-ace-action find-file))
    (define-key embark-buffer-map   (kbd "o") (my/embark-ace-action switch-to-buffer))
    (define-key embark-bookmark-map (kbd "o") (my/embark-ace-action bookmark-jump))
    
    (define-key embark-file-map     (kbd "2") (my/embark-split-action find-file split-window-below))
    (define-key embark-buffer-map   (kbd "2") (my/embark-split-action switch-to-buffer split-window-below))
    (define-key embark-bookmark-map (kbd "2") (my/embark-split-action bookmark-jump split-window-below))
    
    (define-key embark-file-map     (kbd "3") (my/embark-split-action find-file split-window-right))
    (define-key embark-buffer-map   (kbd "3") (my/embark-split-action switch-to-buffer split-window-right))
    (define-key embark-bookmark-map (kbd "3") (my/embark-split-action bookmark-jump split-window-right))
    
  • Keybindings (CTRL C-w Window)

    Inspired by Tecosaur.

    (map! :map evil-window-map
          "SPC" #'rotate-layout
          "e" #'jp/hydra/windows/body
          ;; Navigation
          "<left>"     #'evil-window-left
          "<down>"     #'evil-window-down
          "<up>"       #'evil-window-up
          "<right>"    #'evil-window-right
          "H-<left>"     #'evil-window-left
          "H-<down>"     #'evil-window-down
          "H-<up>"       #'evil-window-up
          "H-<right>"    #'evil-window-right
          ;; Swapping windows
          "C-<left>"       #'+evil/window-move-left
          "C-<down>"       #'+evil/window-move-down
          "C-<up>"         #'+evil/window-move-up
          "C-<right>"      #'+evil/window-move-right
          )
    
    

Evil Mode Bindings

(unbind-key "K" evil-normal-state-map)
(unbind-key "K" evil-visual-state-map)
(map! :nv "gK"  #'+lookup/documentation)

Doom Dashboard

  • Other (g / z)
    (map! :nv "gr" #'org-babel-tangle)
    
    
  • Hyper Key
    • Remapping Important Keys
      (progn
        (define-key key-translation-map (kbd "H-<next>") (kbd "<next>"))
        (define-key key-translation-map (kbd "H-<prior>") (kbd "<prior>"))
        (define-key key-translation-map (kbd "H-<end>") (kbd "<end>"))
        (define-key key-translation-map (kbd "H-<home>") (kbd "<home>"))
        (define-key key-translation-map (kbd "H-<escape>") (kbd "<escape>"))
        (define-key key-translation-map (kbd "H-ü") (kbd "<escape>"))
        (define-key key-translation-map (kbd "H-<left>") (kbd "<left>"))
        (define-key key-translation-map (kbd "H-<right>") (kbd "<right>"))
        (define-key key-translation-map (kbd "H-<up>") (kbd "<up>"))
        (define-key key-translation-map (kbd "H-<down>") (kbd "<down>"))
        (define-key key-translation-map (kbd "H-<backspace>") (kbd "<DEL>"))
        (define-key key-translation-map (kbd "H-<delete>") (kbd "<deletechar>"))
        (define-key key-translation-map (kbd "H-<return>") (kbd "<RET>"))
        (dolist (i '(0 1 2 3 4 5 6 7 8 9))
          (define-key key-translation-map
                      (kbd (format "H-<kp-%d>" i)) (kbd (number-to-string i)))))
      
    • Custom Functions
      (map! "H-¿" #'counsel-ag)                               ; H-s
      (map! "H-<kp-add>" #'jp/org-roam-jump-menu/body)        ; H-q
      (map! "H-¡" #'+hydra/window-nav/body)                   ; H-k
      (map! "H-;" #'hydra-ivy/body)                           ; H-j
      (map! "H-<insert>" #'ivy-mode)                          ; H-ä
      (map! "H-<tab>" #'org-agenda)                           ; H-ö
      (map! "H-<kp-separator>" #'embark-act)                  ; H-d
      (map! "H-<undo>" #'jp/org-roam-refresh-agenda-list)     ; H-z
      

Color Theme

;; (let ((theme-carusell '(
;;                         doom-outrun-electric
;;                         modus-vivendi
;;                         ef-bio
;;                         ef-dark
;;                         ef-deuteranopia-dark
;;                         ef-duo-dark
;;                         ef-night
;;                         ;; ef-autumn
;;                         ;; ef-trio-dark
;;                         ;; ef-tritanopia-dark
;;                         ef-winter)))
(setq doom-theme 'modus-vivendi)

Font Face Configuration

  • New Configuration

    Inspired by Tecosaur.

    (setq doom-font (font-spec :family "Iosevka Term" :size 14)
          doom-big-font (font-spec :family "Iosevka Term" :size 22)
          doom-variable-pitch-font (font-spec :family "Iosevka Aile" :size 16)
          doom-unicode-font (font-spec :family "Iosevka Term" :size 14)
          doom-serif-font (font-spec :family "Iosevka Term" :weight 'light :size 14))
    

Basic Emacs UI Enhancements

  • Line Numbers
    (setq display-line-numbers-type 'relative)
    
    ;; Disable Line Numbers for specific modes
    (dolist (mode '(org-mode-hook
                    term-mode-hook
                    shell-mode-hook
                    eshell-mode-hook))
      (add-hook mode (lambda () (display-line-numbers-mode 0))))
    
    
  • White Spaces

    Inspired by Xah.

    Sometimes I need some additional whitespace information. This function enables all important whitespaces:

    (defun jp/more-whitespaces ()
      (interactive)
      ;; Make whitespace-mode with very basic background coloring for whitespaces.
      (setq whitespace-style (quote (face spaces tabs newline space-mark tab-mark newline-mark)))
    
      ;; Make whitespace-mode and whitespace-newline-mode use “¶” for end of line char and “⇥” for tab.
      (setq whitespace-display-mappings
            ;; all numbers are unicode codepoint in decimal. e.g. (insert-char 182 1)
            '(
              ;; (space-mark 32 [183] [46]) ; SPACE 32 「 」, 183 MIDDLE DOT 「·」, 46 FULL STOP 「.」, 2FD MODIFIER LETTER SHELF 「˽」
              (newline-mark 10 [182 10]) ; LINE FEED ¶
              (tab-mark 9 [8677 9] [92 9]) ; tab ⇥
              ))
      (whitespace-mode 1))
    
    

    Other useful codes:

    char codepoint (decimal) hex name
    · 183 b7 MIDDLE DOT
    182 b6 PILCROW SIGN
    8629 21b5 DOWNWARDS ARROW WITH CORNER LEFTWARDS
    8617 21a9 LEFTWARDS ARROW WITH HOOK
    9166 23ce RETURN SYMBOL
    9655 25b7 WHITE RIGHT POINTING TRIANGLE
    9654 25b6 BLACK RIGHT-POINTING TRIANGLE
    8594 2192 RIGHTWARDS ARROW
    8614 21a6 RIGHTWARDS ARROW FROM BAR
    8677 21e5 RIGHTWARDS ARROW TO BAR
    8680 21e8 RIGHTWARDS WHITE ARROW
  • Visible Bell

    Disable the computer beep and activate a visual feedback instead.

    ;; Set up the visible bell
    (setq visible-bell t)
    
    
  • Alert Styles
    (setq alert-default-style 'osx-notifier)
    
  • Disable Menu Bar

    This allows you to see some basic actions (activates dropdown menus File, Edit, Options, etc.)

    (menu-bar-mode -1)
    
    
  • Enable Mouse (Backward, Forward) Buttons
    (map! :n [mouse-8] #'better-jumper-jump-backward
          :n [mouse-9] #'better-jumper-jump-forward)
    
  • HOLD Resize Startup Window
    (defun jp/set-frame-size-according-to-resolution ()
      (interactive)
      (if window-system
          (progn
            ;; use 120 char wide window for largeish displays
            ;; and smaller 80 column windows for smaller displays
            ;; pick whatever numbers make sense for you
            (if (> (x-display-pixel-width) 1280)
                (add-to-list 'default-frame-alist (cons 'width 177))
              (add-to-list 'default-frame-alist (cons 'width 100)))
            ;; for the height, subtract a couple hundred pixels
            ;; from the screen height (for panels, menubars and
            ;; whatnot), then divide by the height of a char to
            ;; get the height we want
            (add-to-list 'default-frame-alist
                         (cons 'height (/ (- (x-display-pixel-height) 120)
                                          (frame-char-height)))))))
    
    (jp/set-frame-size-according-to-resolution)
    
    
  • Tab Bar
    (setq tab-bar-close-button-show nil
          tab-bar-new-button-show nil)
    

Doom Emacs Customization

  • Confirm Leaving Emacs
    (setq confirm-kill-emacs nil)           ;; Don't confirm every kill
    
  • Doom Evil Mode
    (setq
     evil-want-fine-undo t                  ;; Undo Emacs Style. By default while in insert all changes are one big blob.
     evil-vsplit-window-right t             ;; Split windows the other way around
     evil-split-window-below t)
    
  • Doom Modeline
    • Basic Configuration
      (use-package! doom-modeline
        :custom-face
        (mode-line ((t (:height 1.0))))
        (mode-line-inactive ((t (:height 0.95))))
        :custom
        (doom-modeline-height 16)
        (doom-modeline-bar-width 4)
        (doom-modeline-lsp t)
        (doom-modeline-display-default-persp-name t)
        (doom-modeline-modal-icon t)
        (doom-modeline-minor-modes nil)
        (doom-modeline-major-mode-icon t)
      
        (defun doom-modeline-conditional-buffer-encoding ()
          "We expect the encoding to be LF UTF-8, so only show the modeline when this is not the case"
          (setq-local doom-modeline-buffer-encoding
                      (unless (and (memq (plist-get (coding-system-plist buffer-file-coding-system) :category)
                                         '(coding-category-undecided coding-category-utf-8))
                                   (not (memq (coding-system-eol-type buffer-file-coding-system) '(1 2))))
                        t)))
      
        (add-hook 'after-change-major-mode-hook #'doom-modeline-conditional-buffer-encoding) (doom-modeline-buffer-state-icon t))
      
    • Display Time in Modeline
      (setq display-time-24hr-format t                ;; Display 24 Hrs rather than 12
            display-time-default-load-average nil)    ;; Do not display my CPU Load
      (display-time-mode 0)
      
    • HOLD Display Pomm Timer
      (add-to-list 'mode-line-misc-info '(:eval pomm-current-mode-line-string))
      (add-hook 'pomm-on-tick-hook 'pomm-update-mode-line-string)
      (add-hook 'pomm-on-tick-hook 'force-mode-line-update)
      (add-hook 'pomm-on-status-changed-hook 'pomm-update-mode-line-string)
      (add-hook 'pomm-on-status-changed-hook 'force-mode-line-update)
      
    • TODO Define Modeline

      Possible Values (as stored in doom-modeline-fn-alist):

      Doom Modeline Segment Associated Function
      follow doom-modeline-segment--follow
      grip doom-modeline-segment--grip
      git-timemachine doom-modeline-segment--git-timemachine
      helm-follow doom-modeline-segment--helm-follow
      helm-prefix-argument doom-modeline-segment--helm-prefix-argument
      helm-help doom-modeline-segment--helm-help
      helm-number doom-modeline-segment--helm-number
      helm-buffer-id doom-modeline-segment--helm-buffer-id
      package doom-modeline-segment--package
      battery doom-modeline-segment--battery
      irc doom-modeline-segment--irc
      irc-buffers doom-modeline-segment--irc-buffers
      gnus doom-modeline-segment--gnus
      mu4e doom-modeline-segment--mu4e
      pdf-pages doom-modeline-segment--pdf-pages
      debug doom-modeline-segment--debug
      github doom-modeline-segment--github
      lsp doom-modeline-segment--lsp
      repl doom-modeline-segment--repl
      info-nodes doom-modeline-segment--info-nodes
      input-method doom-modeline-segment--input-method
      objed-state doom-modeline-segment--objed-state
      modals doom-modeline-segment--modals
      parrot doom-modeline-segment--parrot
      buffer-position doom-modeline-segment--buffer-position
      misc-info doom-modeline-segment--misc-info
      persp-name doom-modeline-segment--persp-name
      workspace-name doom-modeline-segment--workspace-name
      window-number doom-modeline-segment--window-number
      hud doom-modeline-segment--hud
      bar doom-modeline-segment--bar
      media-info doom-modeline-segment--media-info
      buffer-size doom-modeline-segment--buffer-size
      matches doom-modeline-segment--matches
      selection-info doom-modeline-segment--selection-info
      word-count doom-modeline-segment--word-count
      checker doom-modeline-segment--checker
      vcs doom-modeline-segment--vcs
      minor-modes doom-modeline-segment--minor-modes
      process doom-modeline-segment--process
      major-mode doom-modeline-segment--major-mode
      remote-host doom-modeline-segment--remote-host
      indent-info doom-modeline-segment--indent-info
      buffer-encoding doom-modeline-segment--buffer-encoding
      buffer-default-directory-simple doom-modeline-segment--buffer-default-directory-simple
      buffer-default-directory doom-modeline-segment--buffer-default-directory
      buffer-info-simple doom-modeline-segment--buffer-info-simple
      buffer-info doom-modeline-segment--buffer-info
      (after! doom-modeline
        (doom-modeline-def-modeline 'jp
          '(bar matches buffer-info remote-host buffer-position parrot selection-info)
          '(misc-info minor-modes checker input-method buffer-encoding major-mode process vcs "  ")))
      
  • Doom Dashboard
    • Keybindings
      Key Function
      f find-file
      r consult-recent-file
      p jp/go-to-projects
      c jp/go-to-config
      i jp/go-to-inbox
      . (cmd! (doom-project-find-file "~/.config/"))
      b +vertico/switch-workspace-buffer
      B counsel-switch-buffer
      (map! :map +doom-dashboard-mode-map
            :ne "f" #'find-file
            :ne "r" #'consult-recent-file
            :ne "p" #'jp/go-to-projects
            :ne "c" #'jp/go-to-config
            :ne "i" #'jp/go-to-inbox
            :ne "." (cmd! (doom-project-find-file "~/.config/")) ; . for dotfiles
            :desc "Notes (roam)" :ne "n" #'org-roam-node-find
            :desc "Open dotfile" :ne "d" (cmd! (doom-project-find-file "~/.dotfiles/"))
            :desc "IBuffer" :ne "i" #'ibuffer
            :desc "ivy-mode" :ne "I" #'ivy-mode
            :desc "Previous buffer" :ne "p" #'previous-buffer
            :desc "Set theme" :ne "t" #'consult-theme
            :ne "b" #'+vertico/switch-workspace-buffer
            :ne "B" #'counsel-switch-buffer)
      
    • Menu Sections
      (after! all-the-icons
        (setq +doom-dashboard-menu-sections '(("Reload last session" :icon
                                               (all-the-icons-octicon "history" :face 'doom-dashboard-menu-title)
                                               :when
                                               (cond
                                                ((featurep! :ui workspaces)
                                                 (file-exists-p
                                                  (expand-file-name persp-auto-save-fname persp-save-dir)))
                                                ((require 'desktop nil t)
                                                 (file-exists-p
                                                  (desktop-full-file-name))))
                                               :face
                                               (:inherit
                                                (doom-dashboard-menu-title bold))
                                               :action doom/quickload-session)
                                              ("Open org-agenda" :icon
                                               (all-the-icons-octicon "calendar" :face 'doom-dashboard-menu-title)
                                               :action org-agenda)
                                              ("Open Roam Notes" :icon
                                               (all-the-icons-octicon "search"
                                                                      :face 'doom-dashboard-menu-title)
                                               :action org-roam-node-find)
                                              ("Open IBuffer" :icon
                                               (all-the-icons-octicon "list-unordered"
                                                                      :face 'doom-dashboard-menu-title)
                                               :action ibuffer)
                                              ("Refresh Agenda Files" :icon
                                               (all-the-icons-octicon "database"
                                                                      :face 'doom-dashboard-menu-title)
                                               :action jp/org-roam-refresh-agenda-list)
                                              ("Recently opened files" :icon
                                               (all-the-icons-octicon "file-text" :face 'doom-dashboard-menu-title)
                                               :action recentf-open-files)
                                              ("Open project" :icon
                                               (all-the-icons-octicon "briefcase" :face 'doom-dashboard-menu-title)
                                               :action projectile-switch-project)
                                              ("Jump to bookmark" :icon
                                               (all-the-icons-octicon "bookmark" :face 'doom-dashboard-menu-title)
                                               :action bookmark-jump)
                                              ("Open private configuration" :icon
                                               (all-the-icons-octicon "tools" :face 'doom-dashboard-menu-title)
                                               :when
                                               (file-directory-p doom-private-dir)
                                               :action doom/open-private-config)
                                              ("Switch Workspace Buffer" :icon
                                               (all-the-icons-octicon "file-symlink-file" :face 'doom-dashboard-menu-title)
                                               :action +vertico/switch-workspace-buffer)
                                              ("Switch Buffer" :icon
                                               (all-the-icons-octicon "file-symlink-directory" :face 'doom-dashboard-menu-title)
                                               :action counsel-switch-buffer))))
      
      

Additional Packages

  • Highlight Todos
    (setq hl-todo-keyword-faces
          '(("TODO"   . "#cc00cc")     ;; TODO
            ("FIXME"  . "#990000")    ;; FIXME
            ("NOTE"   . "#009999")    ;; NOTE
            ("REVIEW" . "#990099")    ;; REVIEW
            ("DEBUG"  . "#A020F0")    ;; DEBUG
            ("HACK"   . "#ff6600")       ;; HACK
            ("GOTCHA" . "#FF4500")    ;; GOTCHA
            ("STUB"   . "#1E90FF")))   ;; STUB
    
    (hl-todo-mode)          ; Enable highlight todos
    
    
  • Spell-Checking (aspell)
    (setq ispell-program-name (executable-find "aspell"))
    
  • PDF Tools
    (pdf-tools-install)
    
    ;; Fit PDF in screen width
    ;; (setq pdf-view-display-size 'fit-width)
    
    ;; Show PDF in current Theme Colors
    ;; (add-hook 'pdf-view-mode-hook (lambda() (pdf-view-themed-minor-mode)))
    
    ;; Cut off unwritten borders of PDF.
    ;; (add-hook 'pdf-view-mode-hook (lambda() (pdf-view-auto-slice-minor-mode)))
    
    
  • nov.el (EPUB)
    ;; Open .epub with nov.el package
    (add-to-list 'auto-mode-alist '("\\.epub\\'" . nov-mode))
    
    ;; Set custom font for epub
    (defun my-nov-font-setup ()
      (face-remap-add-relative 'variable-pitch :family "Roboto"
                               :height 1.0))
    (add-hook 'nov-mode-hook 'my-nov-font-setup)
    
  • WAIT SVG Tag Mode

    Not working with Doom Emacs yet. Follow Issue on Github→ for further information.

    • Example 1
      (require 'svg-tag-mode)
      
      (defface svg-tag-note-face
        '((t :foreground "black" :background "white" :box "black"
             :family "JuliaMono" :weight light :height 140))
        "Face for note tag" :group nil)
      
      (defface svg-tag-keyboard-face
        '((t :foreground "#333333" :background "#f9f9f9" :box "#333333"
             :family "JuliaMono" :weight light :height 140))
        "Face for keyboard bindings tag" :group nil)
      
      (defface svg-tag-org-face
        '((t :foreground "#333333" :background "#fffff0" :box "#333333"
             :family "JuliaMono" :weight light :height 140))
        "Face for keyboard bindings tag" :group nil)
      
      (setq svg-tag-todo
            (svg-tag-make "TODO" nil 1 1 2))
      
      (setq svg-tag-note
            (svg-tag-make "NOTE" 'svg-tag-note-face 2 0 2))
      
      (defun svg-tag-round (text)
        (svg-tag-make (substring text 1 -1) 'svg-tag-note-face 1 1 12))
      
      (defun svg-tag-quasi-round (text)
        (svg-tag-make (substring text 1 -1) 'svg-tag-note-face 1 1 8))
      
      (defun svg-tag-keyboard (text)
        (svg-tag-make (substring text 1 -1) 'svg-tag-keyboard-face 1 1 2))
      
      (defun svg-tag-org (text)
        (svg-tag-make (substring text 1 -1) 'svg-tag-org-face 1 1 2))
      
      (setq svg-tag-tags
            '(("@[0-9a-zA-Z]+:"                   . svg-tag-org)
              (":TODO:"                           . svg-tag-todo)
              (":NOTE:"                           . svg-tag-note)
              ("\([0-9a-zA-Z]\)"                  . svg-tag-round)
              ("\([0-9a-zA-Z][0-9a-zA-Z]\)"       . svg-tag-quasi-round)
              ("|[0-9a-zA-Z- ⇥></%⌘^→←↑↓]+?|"    . svg-tag-keyboard)))
      
      (svg-tag-mode 1)
      
      ;; More examples:
      ;; --------------
      ;;
      ;;  Save ................. |C-x||C-s|  Help ............... |C-h|
      ;;  Save as .............. |C-x||C-w|  Cancel ............. |C-g|
      ;;  Open a new file ...... |C-x||C-f|  Undo ............... |C-z|
      ;;  Open recent .......... |C-x||C-r|  Close buffer ....... |C-x||k|
      ;;  Browse directory ......|C-x||d|    Quit ............... |C-x||C-c|
      ;;
      ;; ------------------------------------------------------------------------
      ;; (1)(2)(3)(4)(5)(Z)(W)(12)(99)
      ;; ------------------------------------------------------------------------
      
      
    • Example 2
      (require 'svg-tag-mode)
      
      (defface svg-tag-org-face
        '((t :foreground "#333333" :background "white"
             :box (:line-width 1 :color "black" :style nil)
             :family "JuliaMono" :weight regular :height 140))
        "Default face for svg tag" :group nil)
      
      (defface svg-tag-note-face
        '((t :foreground "#333333" :background "#FFFFFF"
             :box (:line-width 1 :color "#333333" :style nil)
             :family "JuliaMono" :weight regular :height 140))
        "Default face for svg tag" :group nil)
      
      (defface svg-tag-todo-face
        '((t :foreground "#ffffff" :background "#FFAB91"
             :box (:line-width 1 :color "#FFAB91" :style nil)
             :family "JuliaMono" :weight regular :height 140))
        "Face for TODO  svg tag" :group nil)
      
      (defface svg-tag-next-face
        '((t :foreground "white" :background "#673AB7"
             :box (:line-width 1 :color "#673AB7" :style nil)
             :family "JuliaMono" :weight regular :height 140))
        "Face for NEXT svg tag" :group nil)
      
      (defface svg-tag-done-face
        '((t :foreground "white" :background "#B0BEC5"
             :box (:line-width 1 :color "#B0BEC5" :style nil)
             :family "JuliaMono" :weight regular :height 140))
        "Face for DONE  svg tag" :group nil)
      
      (defface svg-tag-org-tag-face
        '((t :foreground "#ffffff" :background "#FFAB91"
             :box (:line-width 1 :color "#FFAB91" :style nil)
             :family "JuliaMono" :weight regular :height 140))
        "Face for TODO  svg tag" :group nil)
      
      (defface svg-tag-date-active-face
        '((t :foreground "white" :background "#673AB7"
             :box (:line-width 1 :color "#673AB7" :style nil)
             :family "JuliaMono" :weight regular :height 140))
        "Face for active date svg tag" :group nil)
      
      (defface svg-tag-time-active-face
        '((t :foreground "#673AB7" :background "#ffffff"
             :box (:line-width 1 :color "#673AB7" :style nil)
             :family "JuliaMono" :weight light :height 140))
        "Face for active time svg tag" :group nil)
      
      (defface svg-tag-date-inactive-face
        '((t :foreground "#ffffff" :background "#B0BEC5"
             :box (:line-width 1 :color "#B0BEC5" :style nil)
             :family "JuliaMono" :weight regular :height 140))
        "Face for inactive date svg tag" :group nil)
      
      (defface svg-tag-time-inactive-face
        '((t :foreground "#B0BEC5" :background "#ffffff"
             :box (:line-width 2 :color "#B0BEC5" :style nil)
             :family "JuliaMono" :weight light :height 140))
        "Face for inactive time svg tag" :group nil)
      
      (setq svg-tag-org-todo (svg-tag-make "TODO" 'svg-tag-todo-face 1 1 2))
      (setq svg-tag-org-done (svg-tag-make "DONE" 'svg-tag-done-face 1 1 2))
      (setq svg-tag-org-hold (svg-tag-make "HOLD" 'svg-tag-org-face 1 1 2))
      (setq svg-tag-org-next (svg-tag-make "NEXT" 'svg-tag-next-face 1 1 2))
      (setq svg-tag-org-note-tag (svg-tag-make "NOTE" 'svg-tag-note-face 1 1 2))
      (setq svg-tag-org-canceled-tag (svg-tag-make "CANCELED" 'svg-tag-note-face 1 1 2))
      
      (defun svg-tag-make-org-tag (text)
        (svg-tag-make (substring text 1 -1) 'svg-tag-org-tag-face 1 1 2))
      (defun svg-tag-make-org-priority (text)
        (svg-tag-make (substring text 2 -1) 'svg-tag-org-face 1 0 2))
      
      (defun svg-tag-make-org-date-active (text)
        (svg-tag-make (substring text 1 -1) 'svg-tag-date-active-face 0 0 0))
      (defun svg-tag-make-org-time-active (text)
        (svg-tag-make (substring text 0 -1) 'svg-tag-time-active-face 1 0 0))
      (defun svg-tag-make-org-range-active (text)
        (svg-tag-make (substring text 0 -1) 'svg-tag-time-active-face 0 0 0))
      
      (defun svg-tag-make-org-date-inactive (text)
        (svg-tag-make (substring text 1 -1) 'svg-tag-date-inactive-face 0 0 0))
      (defun svg-tag-make-org-time-inactive (text)
        (svg-tag-make (substring text 0 -1) 'svg-tag-time-inactive-face 1 0 0))
      (defun svg-tag-make-org-range-inactive (text)
        (svg-tag-make (substring text 0 -1) 'svg-tag-time-inactive-face 0 0 0))
      
      
      (defconst date-re "[0-9]\\{4\\}-[0-9]\\{2\\}-[0-9]\\{2\\}")
      (defconst time-re "[0-9]\\{2\\}:[0-9]\\{2\\}")
      (defconst day-re "[A-Za-z]\\{3\\}")
      
      (setq svg-tag-tags
            `(("@[0-9a-zA-Z]+:"                   . svg-tag-make-org-tag)
              ("@NOTE:"                           . svg-tag-org-note-tag)
              ("@CANCELED:"                       . svg-tag-org-canceled-tag)
              ("\\[#[ABC]\\]"                     . svg-tag-make-org-priority)
              (" TODO "                           . svg-tag-org-todo)
              (" DONE "                           . svg-tag-org-done)
              (" NEXT "                           . svg-tag-org-next)
              (" HOLD "                           . svg-tag-org-hold)
      
              (,(concat "<" date-re  "[ >]")             . svg-tag-make-org-date-active)
              (,(concat "<" date-re " " day-re "[ >]")   . svg-tag-make-org-date-active)
              (,(concat time-re ">")                     . svg-tag-make-org-time-active)
              (,(concat time-re "-" time-re ">")         . svg-tag-make-org-range-active)
      
              (,(concat "\\[" date-re  "[] ]")           . svg-tag-make-org-date-inactive)
              (,(concat "\\[" date-re " " day-re "[] ]") . svg-tag-make-org-date-inactive)
              (,(concat time-re "\\]")                   . svg-tag-make-org-time-inactive)
              (,(concat time-re "-" time-re "\\]")       . svg-tag-make-org-range-inactive)))
      
      (svg-tag-mode)
      
      
  • Keycast Mode

    Configuration from https://github.com/tarsius/keycast/issues/7#issuecomment-627604064

    (after! keycast
      (require 'keycast)
      (define-minor-mode keycast-mode
        "Show current command and its key binding in the mode line."
        :global t
        (if keycast-mode
            (add-hook 'pre-command-hook 'keycast--update t)
          (remove-hook 'pre-command-hook 'keycast--update))))
    
    (add-to-list 'global-mode-string '("" keycast-mode-line))
    
    
  • Avy
    • Keybindings
      • Default (Evil-)Doom Keybindings

        Avy provides easy movement and actions in buffers. The following Blog post by Karthinks has a lot of awesome examples on how to use Avy. Keybindings to help manage text in buffers.

        Key Action
        g s s evil-avy-goto-char-2
        g s k evilem-motion-previous-line
        g s j evilem-motion-next-line
        g s f evilem-motion-find-char
        g s F evilem-motion-find-char-backward
        g s b evilem-motion-backward-word-begin
        g s B evilem-motion-backward-WORD-begin
        g s ( evilem-motion-backward-sentence-begin
        g s ) evilem-motion-forward-sentence-begin
        g s * evilem-motion-search-word-forward
      • Custom Keybindings

        Also check the various avy- commands under (SPC j):

        Key Action
        SPC j l evil-avy-goto-line
        SPC j c evil-avy-goto-char
        SPC j o evil-avy-goto-char-timer
        SPC j O evil-avy-goto-char-2
        SPC j w evil-avy-goto-word-0
        SPC j W evil-avy-goto-subword-0
      • New Interactions before selecting

        Before selecting the char/word/line/etc., you can press one of these keys to perform an action on your target:

        Key Action
        x -embark
        H -helpful
        = -define
        m -teleport
        M -teleport-whole-line
        k -kill-stay
        K -kill-whole-line
        y -yank
        Y -yank-whole-line
        w -copy
        W -copy-whole-line
    • Home Row Keys for Avy
      ;;(setq avy-keys '(97 115 100 102 103 104 106 107 108))
      (setq avy-keys '(?u ?i ?a ?e ?o ?s ?n ?r ?t))
      
    • Mark to Char (default)
      (require 'avy)
      (defun avy-action-mark-to-char (pt)
        (activate-mark)
        (goto-char pt))
      
      (setf (alist-get ?  avy-dispatch-alist) 'avy-action-mark-to-char)
      
    • Copy / Yank (Paste) / Kill (Cut) Lines
      (defun avy-action-copy-whole-line (pt)
        (save-excursion
          (goto-char pt)
          (cl-destructuring-bind (start . end)
              (bounds-of-thing-at-point 'line)
            (copy-region-as-kill start end)))
        (select-window
         (cdr
          (ring-ref avy-ring 0)))
        t)
      
      (defun avy-action-yank-whole-line (pt)
        (avy-action-copy-whole-line pt)
        (save-excursion (yank))
        t)
      
      (defun avy-action-kill-whole-line (pt)
        (save-excursion
          (goto-char pt)
          (kill-whole-line))
        (select-window
         (cdr
          (ring-ref avy-ring 0)))
        t)
      
      (setf (alist-get ?k avy-dispatch-alist) 'avy-action-kill-stay
            (alist-get ?K avy-dispatch-alist) 'avy-action-kill-whole-line
            (alist-get ?y avy-dispatch-alist) 'avy-action-yank
            (alist-get ?w avy-dispatch-alist) 'avy-action-copy
            (alist-get ?W avy-dispatch-alist) 'avy-action-copy-whole-line
            (alist-get ?Y avy-dispatch-alist) 'avy-action-yank-whole-line)
      
    • Teleport Lines
      (defun avy-action-teleport-whole-line (pt)
        (avy-action-kill-whole-line pt)
        (save-excursion (yank)) t)
      
      (setf (alist-get ?m avy-dispatch-alist) 'avy-action-teleport
            (alist-get ?M avy-dispatch-alist) 'avy-action-teleport-whole-line)
      
    • Search Dictionary
      (defun dictionary-search-dwim (&optional arg)
        "Search for definition of word at point. If region is active,
      search for contents of region instead. If called with a prefix
      argument, query for word to search."
        (interactive "P")
        (if arg
            (dictionary-search nil)
          (if (use-region-p)
              (dictionary-search (buffer-substring-no-properties
                                  (region-beginning)
                                  (region-end)))
            (if (thing-at-point 'word)
                (dictionary-lookup-definition)
              (dictionary-search-dwim '(4))))))
      
      (defun avy-action-define (pt)
        (save-excursion
          (goto-char pt)
          (dictionary-search-dwim))
        (select-window
         (cdr (ring-ref avy-ring 0)))
        t)
      
      (setf (alist-get ?= avy-dispatch-alist) 'avy-action-define)
      
    • Helpful Documentation
      (defun avy-action-helpful (pt)
        (save-excursion
          (goto-char pt)
          (helpful-at-point))
        (select-window
         (cdr (ring-ref avy-ring 0)))
        t)
      
      (setf (alist-get ?H avy-dispatch-alist) 'avy-action-helpful)
      
    • Embark
      (defun avy-action-embark (pt)
        (save-excursion
          (goto-char pt)
          (embark-act))
        (select-window
         (cdr (ring-ref avy-ring 0)))
        t)
      
      (setf (alist-get ?x avy-dispatch-alist) 'avy-action-embark)
      
  • Hydra
    • Windows

      Adapted from

      (defhydra jp/hydra/windows (:hint nil)
        "
                Split: _v_ert  _s_:horz
               Delete: _c_lose  _o_nly
        Switch Window: _h_:left  _j_:down  _k_:up  _l_:right  _u_:undo  _r_:redo
              Buffers: _p_revious  _n_ext  _b_:select  _f_ind-file
               Resize: _H_:splitter left  _J_:splitter down  _K_:splitter up  _L_:splitter right
                 Move: _a_:up  _z_:down  _i_menu
      "
        ("z" scroll-up-line)
        ("a" scroll-down-line)
        ("i" consult-imenu)
      
        ("h" windmove-left)
        ("<left>" windmove-left)
        ("j" windmove-down)
        ("<down>" windmove-down)
        ("k" windmove-up)
        ("<up>" windmove-up)
        ("l" windmove-right)
        ("<right>" windmove-right)
        ("u" winner-undo)
        ("r" winner-redo)
      
        ("p" previous-buffer)
        ("n" next-buffer)
        ("b" switch-to-buffer)
        ("f" find-file)
      
        ("s" split-window-below)
        ("v" split-window-right)
      
        ("c" delete-window)
        ("o" delete-other-windows)
      
        ("H" hydra-move-splitter-left)
        ("J" hydra-move-splitter-down)
        ("K" hydra-move-splitter-up)
        ("L" hydra-move-splitter-right)
      
        ("q" nil))
      
  • Popper
    (after! popper
      (setq popper-reference-buffers
            '("\\*Messages\\*"
              "Output\\*$"
              "\\*Async Shell Command\\*"
              help-mode
              compilation-mode))
      (global-set-key (kbd "C-`") 'popper-toggle-latest)
      (global-set-key (kbd "M-`") 'popper-cycle)
      (global-set-key (kbd "C-M-`") 'popper-toggle-type)
      (popper-mode +1))
    
  • Guix
    (after! guix
      (global-guix-prettify-mode 1))
    
  • Undo Tree
    (setq undo-tree-visualizer-timestamps t) ; Display Timestamps
    

TODO Additional Packages

Dired (File Manager)

Original by Derek Taylor (see dwt1/dotfiles)

Dired Configuration

(add-hook 'peep-dired-hook 'evil-normalize-keymaps)


;; 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 for Dired

  • Keybindings To Open Dired (Description)
    COMMAND DESCRIPTION KEYBINDING
    dired Open dired file manager SPC d d
    dired-jump Jump to current directory in dired SPC d j
  • Keybinding Configuration (SPC-<Key>)
    (map! :leader
          (:prefix ("d" . "dired")
           :desc "Open dired" "d" #'dired
           :desc "Dired jump to current" "j" #'dired-jump)
          (:after dired
           (:map dired-mode-map
            :desc "Peep-dired image previews" "d p" #'peep-dired
            :desc "Dired view file" "d v" #'dired-view-file)))
    
    
  • Keybindings Within Dired (Description)
    COMMAND DESCRIPTION KEYBINDING
    dired-view-file View file in dired SPC d v
    dired-up-directory Go up in directory tree h
    dired-find-file Go down in directory tree (or open if file) l
    dired-next-line Move down to next line j
    dired-previous-line Move up to previous line k
    dired-mark Mark file at point m
    dired-unmark Unmark file at point u
  • Dired-Mode-Mapping
    (defun jp/dired-hide-dotfiles()
        (setq dired-omit-files
              (rx (or (seq bol (? ".") "#")
                      (seq bol "." eol)
                      (seq bol ".." eol)
                      )))
        )
    
    ;; Make 'h' and 'l' go back and forward in dired. Much faster to navigate the directory structure!
    (evil-define-key 'normal dired-mode-map
      (kbd "M-RET") 'dired-display-file
      (kbd "h") 'dired-up-directory
    ;;  (kbd "l") 'dired-open-file ; use dired-find-file instead of dired-open.
      (kbd "m") 'dired-mark
      (kbd "t") 'dired-toggle-marks
      (kbd "u") 'dired-unmark
      (kbd "C") 'dired-do-copy
      (kbd "D") 'dired-do-delete
    ;;  (kbd "H") #'jp/dired-hide-dotfiles
      (kbd "J") 'dired-goto-file
      (kbd "M") 'dired-do-chmod
      (kbd "O") 'dired-do-chown
      (kbd "P") 'dired-do-print
      (kbd "R") 'dired-do-rename
      (kbd "T") 'dired-do-touch
      (kbd "Y") 'dired-copy-filenamecopy-filename-as-kill ; copies filename to kill ring.
      (kbd "+") 'dired-create-directory
      (kbd "-") 'dired-up-directory
      (kbd "% l") 'dired-downcase
      (kbd "% u") 'dired-upcase
      (kbd "; d") 'epa-dired-do-decrypt
      (kbd "; e") 'epa-dired-do-encrypt)
    
    
    ;; If peep-dired is enabled, you will get image previews as you go up/down with 'j' and 'k'
    (evil-define-key 'normal peep-dired-mode-map
      (kbd "j") 'peep-dired-next-file
      (kbd "k") 'peep-dired-prev-file)
    
    

Languages (IDE using Language Server)

IDE Features with lsp-mode

  • lsp-mode

    lsp-mode enables IDE-like functionality for many different programming languages via “language servers” that speak the Language Server Protocol. Before trying to set up lsp-mode for a particular language, check out the documentation for your language so that you can learn which language servers are available and how to install them.

    The lsp-keymap-prefix setting enables you to define a prefix for where lsp-mode’s default keybindings will be added. I highly recommend using the prefix to find out what you can do with lsp-mode in a buffer.

    The which-key integration adds helpful descriptions of the various keys so you should be able to learn a lot just by pressing C-c l in a lsp-mode buffer and trying different things that you find there.

    (defun jp/lsp-mode-setup ()
      (setq lsp-headerline-breadcrumb-segments '(path-up-to-project file symbols))
      (lsp-headerline-breadcrumb-mode))
    
    (use-package lsp-mode
      :commands (lsp lsp-deferred)
      :hook (lsp-mode . jp/lsp-mode-setup)
      :init
      (setq lsp-keymap-prefix "C-c l")  ;; Or 'C-l', 's-l'
      :config
      (lsp-enable-which-key-integration t))
    
    
  • lsp-ui

    lsp-ui is a set of UI enhancements built on top of lsp-mode which make Emacs feel even more like an IDE. Check out the screenshots on the lsp-ui homepage (linked at the beginning of this paragraph) to see examples of what it can do.

    (use-package lsp-ui
      :hook (lsp-mode . lsp-ui-mode)
      :custom
      (lsp-ui-doc-position 'bottom))
    
    
  • lsp-treemacs

    lsp-treemacs provides nice tree views for different aspects of your code like symbols in a file, references of a symbol, or diagnostic messages (errors and warnings) that are found in your code.

    Try these commands with M-x:

    • lsp-treemacs-symbols - Show a tree view of the symbols in the current file
    • lsp-treemacs-references - Show a tree view for the references of the symbol under the cursor
    • lsp-treemacs-error-list - Show a tree view for the diagnostic messages in the project

    This package is built on the treemacs package which might be of some interest to you if you like to have a file browser at the left side of your screen in your editor.

    (use-package lsp-treemacs
      :after lsp)
    
    
  • lsp-ivy

    lsp-ivy integrates Ivy with lsp-mode to make it easy to search for things by name in your code. When you run these commands, a prompt will appear in the minibuffer allowing you to type part of the name of a symbol in your code. Results will be populated in the minibuffer so that you can find what you’re looking for and jump to that location in the code upon selecting the result.

    Try these commands with M-x:

    • lsp-ivy-workspace-symbol - Search for a symbol name in the current project workspace
    • lsp-ivy-global-workspace-symbol - Search for a symbol name in all active project workspaces
    (use-package lsp-ivy
      :after lsp)
    
    

Debugging with dap-mode

dap-mode is an excellent package for bringing rich debugging capabilities to Emacs via the Debug Adapter Protocol. You should check out the configuration docs to learn how to configure the debugger for your language. Also make sure to check out the documentation for the debug adapter to see what configuration parameters are available to use for your debug templates!

(use-package dap-mode
  ;; Uncomment the config below if you want all UI panes to be hidden by default!
  ;; :custom
  ;; (lsp-enable-dap-auto-configure nil)
  ;; :config
  ;; (dap-ui-mode 1)
  :commands dap-debug
  :config
  ;; Set up Node debugging
  (require 'dap-node)
  (dap-node-setup) ;; Automatically installs Node debug adapter if needed

  ;; Bind `C-c l d` to `dap-hydra` for easy access
  (general-define-key
   :keymaps 'lsp-mode-map
   :prefix lsp-keymap-prefix
   "d" '(dap-hydra t :wk "debugger")))

Python

  • General

    We use lsp-mode and dap-mode to provide a more complete development environment for Python in Emacs. Check out the documentation of lsp-pyright in the lsp-mode documentation for more details.

    Make sure you have the lsp-pyright language server installed before trying lsp-mode!

    There are a number of other language servers for Python so if you find that pyls doesn’t work for you, consult the lsp-mode language configuration documentation to try the others!

    (defun jp/python-mode-hook()
      (require 'lsp-pyright)
      (require 'dap-python)
      (modify-syntax-entry ?_ "w") ; treat underscore (_) as word-breaking character
      (lsp-deferred))
    
    (add-hook 'python-mode-hook #'jp/python-mode-hook)
    
    ;; NOTE: Set these if Python 3 is called "python3" on your system!
    (setq dap-python-debugger 'debugpy)
    
  • MacOS

    MacOS has different location thanks to Anaconda:

    (defvar jp/guix/pythonpath (getenv "GUIX_PYTHONPATH")
      "Absolute Python Library Path (e.g. /usr/share/lib/python3.9/site-packages)")
    (defvar jp/conda/pythonpath (getenv "CONDA_PYTHON_EXE")
      "Absolute Conda Python Exe Path (e.g. /opt/miniconda3/bin/python)")
    (defvar jp/conda/prefix (getenv "CONDA_PREFIX")
      "Absolute Path to current Conda Prefix (e.g. /home/user/.conda/envs/my-environment)")
    (defvar jp/python
      (if jp/guix/pythonpath
          (concat (ivy--parent-dir (ivy--parent-dir (ivy--parent-dir jp/guix/pythonpath))) "bin/python3")
        (if jp/conda/prefix
            (concat jp/conda/prefix "/bin/python")
          (if jp/conda/pythonpath
              jp/conda/pythonpath
            "/opt/homebrew/conda/bin/python"
            )))
      "Python binary path.")
    (setq python-shell-interpreter jp/python
          dap-python-executable jp/python
          treemacs-python-executable jp/python
          org-babel-python-command jp/python
          lsp-pyright-python-executable-cmd jp/python)
    
  • Linux

    Linux uses Miniconda3:

    (defvar jp/guix/pythonpath (if (getenv "GUIX_PYTHONPATH")
                                   (getenv "GUIX_PYTHONPATH")
                                 (getenv "PYTHONPATH"))
      "Absolute Python Library Path (e.g. /usr/share/lib/python3.9/site-packages)")
    (defvar jp/conda/pythonpath (getenv "CONDA_PYTHON_EXE")
      "Absolute Conda Python Exe Path (e.g. /opt/miniconda3/bin/python)")
    (defvar jp/conda/prefix (getenv "CONDA_PREFIX")
      "Absolute Path to current Conda Prefix (e.g. /home/user/.conda/envs/my-environment)")
    (defvar jp/python
      (if jp/guix/pythonpath
          (concat (ivy--parent-dir (ivy--parent-dir (ivy--parent-dir jp/guix/pythonpath))) "bin/python3")
        (if jp/conda/prefix
            (concat jp/conda/prefix "/bin/python")
          (if jp/conda/pythonpath
              jp/conda/pythonpath
            (executable-find "python3")
            )))
      "Python binary path.")
    (setq python-shell-interpreter jp/python
          dap-python-executable jp/python
          treemacs-python-executable jp/python
          lsp-pyright-python-executable-cmd jp/python
          python-check-command (file-truename "~/.local/bin/epylint"))
    
  • PyEnv

    You can use the pyvenv package to use virtualenv environments in Emacs. The pyvenv-activate command should configure Emacs to cause lsp-mode and dap-mode to use the virtual environment when they are loaded, just select the path to your virtual environment before loading your project.

    (use-package pyvenv
      :after python-mode
      :config
      (pyvenv-mode 1)
      (setq pyvenv-virtualenvwrapper-python jp/python))
    
    
  • Anaconda
    ;; Anaconda Path
    (setq conda-env-home-directory "/opt/homebrew/Caskroom/miniforge/base"
          conda-anaconda-home conda-env-home-directory)
    

TODO TypeScript (deactivated)

This is a basic configuration for the TypeScript language so that .ts files activate typescript-mode when opened. We’re also adding a hook to typescript-mode-hook to call lsp-deferred so that we activate lsp-mode to get LSP features every time we edit TypeScript code.

(use-package typescript-mode
  :mode "\\.ts\\'"
  :hook (typescript-mode . lsp-deferred)
  :config
  (setq typescript-indent-level 2))

Important note! For lsp-mode to work with TypeScript (and JavaScript) you will need to install a language server on your machine. If you have Node.js installed, the easiest way to do that is by running the following command:

npm install -g typescript-language-server typescript

This will install the typescript-language-server and the TypeScript compiler package.

Company Mode (Autocompletion)

Company Mode provides a nicer in-buffer completion interface than completion-at-point which is more reminiscent of what you would expect from an IDE. We add a simple configuration to make the keybindings a little more useful (TAB now completes the selection and initiates completion at the current location if needed).

We also use company-box to further enhance the look of the completions with icons and better overall presentation.

(use-package company
  :after lsp-mode
  :hook (lsp-mode . company-mode)
  :bind (:map company-active-map
         ("<tab>" . company-complete-selection))
  (:map lsp-mode-map
   ("<tab>" . company-indent-or-complete-common))
  :custom
  (company-minimum-prefix-length 1)
  (company-idle-delay 0.0))

(use-package company-box
  :hook (company-mode . company-box-mode))

Projectile

;; NOTE: Set this to the folder where you keep your Git repos!
(when (file-directory-p "~/Projects/Code")
  (setq projectile-project-search-path '("~/Projects/Code")))
(setq projectile-switch-project-action #'projectile-dired)

(setq projectile-completion-system 'auto)

Eshell

Adapted from daviwil/emacs-from-scratch.

Eshell is Emacs’ own shell implementation written in Emacs Lisp. It provides you with a cross-platform implementation (even on Windows!) of the common GNU utilities you would find on Linux and macOS (ls, rm, mv, grep, etc). It also allows you to call Emacs Lisp functions directly from the shell and you can even set up aliases (like aliasing vim to find-file). Eshell is also an Emacs Lisp REPL which allows you to evaluate full expressions at the shell.

The downsides to Eshell are that it can be harder to configure than other packages due to the particularity of where you need to set some options for them to go into effect, the lack of shell completions (by default) for some useful things like Git commands, and that REPL programs sometimes don’t work as well. However, many of these limitations can be dealt with by good configuration and installing external packages, so don’t let that discourage you from trying it!

Useful key bindings:

  • C-c C-p / C-c C-n - go back and forward in the buffer’s prompts (also [[ and ]] with evil-mode)
  • M-p / M-n - go back and forward in the input history
  • C-c C-u - delete the current input string backwards up to the cursor
  • counsel-esh-history - A searchable history of commands typed into Eshell

We will be covering Eshell more in future videos highlighting other things you can do with it.

For more thoughts on Eshell, check out these articles by Pierre Neidhardt:

(defun jp/configure-eshell ()
  ;; Save command history when commands are entered
  (add-hook 'eshell-pre-command-hook 'eshell-save-some-history)

  ;; Truncate buffer for performance
  (add-to-list 'eshell-output-filter-functions 'eshell-truncate-buffer)

  ;; Bind some useful keys for evil-mode
  (evil-define-key '(normal insert visual) eshell-mode-map (kbd "C-r") 'counsel-esh-history)
  (evil-define-key '(normal insert visual) eshell-mode-map (kbd "<home>") 'eshell-bol)
  (evil-normalize-keymaps)

  (setq eshell-history-size         10000
        eshell-buffer-maximum-lines 10000
        eshell-hist-ignoredups t
        eshell-scroll-to-bottom-on-input t))

(use-package eshell-git-prompt
  :after eshell)

(use-package eshell
  :hook (eshell-first-time-mode . jp/configure-eshell)
  :config

  (with-eval-after-load 'esh-opt
    (setq eshell-destroy-buffer-when-process-dies t)
    (setq eshell-visual-commands '("htop" "zsh" "vim")))

  (eshell-git-prompt-use-theme 'powerline))


Magit

(after! magit
  (remove-hook 'server-switch-hook 'magit-commit-diff)
  )

;; Magit Configuration to enable gpg to sign keys
(unless jp/guix?
  (progn
    (setenv "PATH" (concat (getenv "PATH") ":/usr/local/bin"))
    (setq exec-path (append exec-path '("/usr/local/bin")))))

Mail in Emacs with mu4e

Adapted from daviwil/dotfiles.

mu4e is the best mail interface I’ve ever used because it’s fast and makes it really easy to power through a huge e-mail backlog. Love the ability to capture links to emails with org-mode too.

Useful mu4e manual pages:

;; Tell Emacs where to find mu4e (only necessary if manual compiled)
(pcase system-type
  ((or 'gnu/linux 'windows-nt 'cygwin)
   (unless jp/guix?
     (add-to-list 'load-path "/usr/share/emacs/site-lisp/mu4e")))
  ('darwin
   (use-package mu4e
     :load-path  "/opt/homebrew/share/emacs/site-lisp/mu/mu4e/")))

;; Load org-mode integration
;;(require 'mu4e-org)

(after! mu4e
  ;; Refresh mail using isync every 10 minutes
  (setq mu4e-update-interval (* 10 60))
  (setq mu4e-get-mail-command "mbsync -a")
  (setq mu4e-maildir "~/Mail")

  ;; Use Ivy for mu4e completions (maildir folders, etc)
  ;;(setq mu4e-completing-read-function #'ivy-completing-read)

  ;; Make sure that moving a message (like to Trash) causes the
  ;; message to get a new file name.  This helps to avoid the
  ;; dreaded "UID is N beyond highest assigned" error.
  ;; See this link for more info: https://stackoverflow.com/a/43461973
  (setq mu4e-change-filenames-when-moving t)

  ;; Make sure to use 24h time format.
  (setq mu4e-headers-time-format "%T" ; %T: Full 24h-Time [same as %H:%M:%S] (e.g. 23:59:59)
        mu4e-headers-date-format "%d/%m/%y"
        ;;mu4e-view-date-format "%F %T" ; %F: Full date [like %+4Y-%m-%d] (e.g. 2021-12-31)
        ;;mu4e-date-format-long "%F %T"
        ;;mu4e-headers-long-date-format "%F %T"
        )

  ;; Set up contexts for email accounts
  (setq mu4e-contexts
        `(,(make-mu4e-context
            :name "Mailbox"
            :match-func (lambda (msg) (when msg
                                        (string-prefix-p "/Mailbox" (mu4e-message-field msg :maildir))))
            :vars '(
                    (user-full-name . "Jonathan Pieper")
                    (user-mail-address . "jpieper@mailbox.org")
                    (mu4e-sent-folder . "/Mailbox/Sent")
                    (mu4e-trash-folder . "/Mailbox/Trash")
                    (mu4e-drafts-folder . "/Mailbox/Drafts")
                    (mu4e-refile-folder . "/Mailbox/Archives")
                    (mu4e-sent-messages-behavior . sent)
                    ))
          ,(make-mu4e-context
            :name "Personal"
            :match-func (lambda (msg) (when msg
                                        (string-prefix-p "/Personal" (mu4e-message-field msg :maildir))))
            :vars '(
                    (mu4e-sent-folder . "/Personal/Sent")
                    (mu4e-trash-folder . "/Personal/Deleted")
                    (mu4e-refile-folder . "/Personal/Archive")
                    ))
          ))
  (setq mu4e-context-policy 'pick-first)

  ;; Prevent mu4e from permanently deleting trashed items
  ;; This snippet was taken from the following article:
  ;; http://cachestocaches.com/2017/3/complete-guide-email-emacs-using-mu-and-/
  (defun remove-nth-element (nth list)
    (if (zerop nth) (cdr list)
      (let ((last (nthcdr (1- nth) list)))
        (setcdr last (cddr last))
        list)))

  ;; Display options
  (setq mu4e-view-show-images t)
  (setq mu4e-view-show-addresses 't)

  ;; Composing mail
  (setq mu4e-compose-dont-reply-to-self t)

  ;; Use mu4e for sending e-mail
  (setq mail-user-agent 'mu4e-user-agent
        message-send-mail-function 'smtpmail-send-it
        smtpmail-smtp-server "smtp.mailbox.org"
        smtpmail-smtp-service 465
        smtpmail-stream-type  'ssl)

  ;; Signing messages (use mml-secure-sign-pgpmime)
  (setq mml-secure-openpgp-signers '("2361DFC839413E7A84B2152B01B6FB927AAEC59B"))
  (defun sign-or-encrypt-message ()
    (let ((answer (read-from-minibuffer "Sign or encrypt?\nEmpty to do nothing.\n[s/e]: ")))
      (cond
       ((string-equal answer "s") (progn
                                    (message "Signing message.")
                                    (mml-secure-message-sign-pgpmime)))
       ((string-equal answer "e") (progn
                                    (message "Encrypt and signing message.")
                                    (mml-secure-message-encrypt-pgpmime)))
       (t (progn
            (message "Dont signing or encrypting message.")
            nil)))))

  (add-hook 'message-send-hook 'sign-or-encrypt-message)

  ;; (See the documentation for `mu4e-sent-messages-behavior' if you have
  ;; additional non-Gmail addresses and want assign them different
  ;; behavior.)

  ;; setup some handy shortcuts
  ;; you can quickly switch to your Inbox -- press ``ji''
  ;; then, when you want archive some messages, move them to
  ;; the 'All Mail' folder by pressing ``ma''.
  (setq mu4e-maildir-shortcuts
        '(("/Mailbox/INBOX"       . ?i)
          ("/Mailbox/INBOX/*"     . ?l)
          ("/Mailbox/Sent"        . ?s)
          ("/Mailbox/Trash"       . ?t)))

  ;; (add-to-list 'mu4e-bookmarks
  (mu4e-bookmark-define
    "All Inboxes"
    "maildir:/Mailbox/INBOX OR maildir:/Personal/Inbox AND NOT flag:trashed"
    ?i)

  ;; (add-to-list 'mu4e-bookmarks
  (mu4e-bookmark-define
    "from:/.*@uni-frankfurt/ OR maildir:/Personal/Uni"
    "Uni-Frankfurt"
    ?g)

  ;; don't keep message buffers around
  (setq message-kill-buffer-on-exit t)

  (setq jp/mu4e-inbox-query
        "(maildir:/Personal/Inbox OR maildir:/Mailbox/INBOX) AND flag:unread AND NOT flag:trashed")

  (defun jp/go-to-inbox ()
    (interactive)
    (mu4e-headers-search jp/mu4e-inbox-query)

    (setq mu4e-marks (remove-nth-element 5 mu4e-marks))
    (add-to-list 'mu4e-marks
                 '(trash
                   :char ("d" . "▼")
                   :prompt "dtrash"
                   :dyn-target (lambda (target msg) (mu4e-get-trash-folder msg))
                   :action (lambda (docid msg target)
                             (mu4e~proc-move docid
                                             (mu4e~mark-check-target target) "-N"))))

    ;; Use [[https://github.com/iqbalansari/mu4e-alert][mu4e-alert]]
    ;; to show notifications when e-mail comes in.
    ;; Show unread emails from all inboxes
    (setq mu4e-alert-interesting-mail-query jp/mu4e-inbox-query)

    ;; Show notifications for mails already notified
    (setq mu4e-alert-notify-repeated-mails nil)

    (mu4e-alert-enable-notifications)))

Password Save

(setq auth-sources '("~/.authinfo.gpg")
      auth-source-cache-expiry nil)

(defun jp/lookup-password (&rest keys)
  (let ((result (apply #'auth-source-search keys)))
    (if result
        (funcall (plist-get (car result) :secret))
      nil)))

(defun jp/enable-bitwarden ()
  (interactive)
  (setq bitwarden-automatic-unlock
        (let* ((auth-sources '("~/.authinfo.gpg"))
               (matches (auth-source-search :user "jpieper@mailbox.org"
                                            :host "bw.ody5.de"
                                            :require '(:secret)
                                            :max 1))
               (entry (nth 0 matches)))
          (plist-get entry :secret)))
  (bitwarden-auth-source-enable))

Deft

(setq deft-directory "~/org")

Finances

Ledger (Financial Support)

(setq jp/decrypt-ledger "")
(with-eval-after-load 'company
  (add-to-list 'company-backends 'company-ledger))

(setq ledger-reconcile-default-commodity "€")

(setq ledger-reports
 '(("bal"            "gpg --decrypt %(ledger-file) 2>/dev/null | %(binary) -f - bal")
   ("bal this month" "gpg --decrypt %(ledger-file) 2>/dev/null | %(binary) -f - bal -p %(month) -S amount")
   ("bal this year"  "gpg --decrypt %(ledger-file) 2>/dev/null | %(binary) -f - bal -p 'this year'")
   ("net worth"      "gpg --decrypt %(ledger-file) 2>/dev/null | %(binary) -f - bal Assets Liabilities")
   ("reg"        "gpg --decrypt %(ledger-file) 2>/dev/null | %(binary) -f %(ledger-file) reg")
   ("account"        "gpg --decrypt %(ledger-file) 2>/dev/null | %(binary) -f %(ledger-file) reg %(account)")))

(map! :map ledger-reconcile-mode-map
      :ne "q" #'ledger-reconcile-quit
      :ne "a" #'ledger-reconcile-add
      :ne "d" #'ledger-reconcile-delete)

Beancount

Beancount is a CLI Tool written in Python to manage finances.

(map!
      :map beancount-mode-map
       (:prefix "m"
        :desc "Insert Date" :n "i" #'beancount-insert-date
        :desc "Query" :n "q" #'beancount-query
        ))

HOLD Scimax

(setq scimax-dir (file-truename "~/build/scimax"))
(add-to-list 'load-path (file-truename "~/build/scimax"))
(require 'f)
(require 'scimax)
(scimax-update)

Comments

Date: 2022-05-28 (Last update: 2024-11-23)

Made with Emacs 29.4 (Org mode 9.7.14)

© 2021-2024 Jonathan Pieper GNU General Public License Creative Commons License