GNU/Emacs

about | blog | config | notes | github

1. The Extensible, Customizable Free/Libre Text Editor

emacs_logo.png

2. Useful Resources

3. Tips and Tricks

As I find things to write here, I'll put it in.

4. Configuration

4.1. Garbage Collector Hooks

Supposedly makes the startup a bit more effecient. We also revert the changes to the GC via a hook once the startup has completed.

(defvar file-name-handler-alist-original file-name-handler-alist)

(setq gc-cons-threshold most-positive-fixnum
      gc-cons-percentage 0.6
      file-name-handler-alist nil
      site-run-file nil)

(defvar zamlz/gc-cons-threshold 100000000)

(add-hook 'emacs-startup-hook ; hook run after loading init files
          (lambda ()
            (setq gc-cons-threshold zamlz/gc-cons-threshold
                  gc-cons-percentage 0.1
                  file-name-handler-alist file-name-handler-alist-original)))

(add-hook 'minibuffer-setup-hook
          (lambda ()
            (setq gc-cons-threshold (* zamlz/gc-cons-threshold 2))))
(add-hook 'minibuffer-exit-hook
          (lambda ()
            (garbage-collect)
            (setq gc-cons-threshold zamlz/gc-cons-threshold)))

4.2. Update Load Path

Optimize: Force lisp and site-lisp at the head to reduce the startup time.

(defun update-load-path (&rest _)
  "Update `load-path'."
  (dolist (dir '("site-lisp" "lisp"))
    (push (expand-file-name dir user-emacs-directory) load-path)))

(update-load-path)

Make sure to populate the lisp and site-lisp directories.

#PLACEHOLDER FILE FOR LISP DIR

4.3. Package Management

I originally was using the internal package.el that is a part of Emacs, but while simple and straightforward to use, it has some limitations. I have found that it may be better to make use of straight.el.

(require 'init-straight)

4.4. Internal

;;(require 'init-package) ;; CONTAINS OLD USE PACKAGE SETUP
(require 'init-dired)
(require 'init-ibuffer)

4.4.1. Reorganize This

  1. Basic Emacs Setup

    Lets get some basic settings out of the way here.

    (use-package emacs
      :preface
      ;; Setup personal preferances
      (defvar zamlz/indent-width 4)   ; tab size
      (defvar zamlz/default-screen-width 100)
      :custom
      ;; Configure personal information
      (user-full-name "Amlesh Sivanantham")
      (user-mail-address "[email protected]")
      (user-login-name "zamlz")
      ;; Other basic settings
      (ring-bell-function 'ignore) ; minimise distractio
      (frame-resize-pixelwise t)
      (default-directory "~/")
      :config
      ;; Set Environment Variables
      (setenv "PINENTRY_USER_DATA" "rofi")
      (setenv "VISUAL" "emacsclient --socket-name=xorg-emacs-daemon" )
      (setenv "EDITOR" (getenv "VISUAL"))
      ;; Configure Specific UI changes
      (tool-bar-mode -1)          ; Disable the toolbar
      (menu-bar-mode -1)          ; disable the menubar
      (set-fringe-mode 10)        ; Give some breathing room
      (blink-cursor-mode 1)       ; Let the cursor be blinking
      (semantic-mode 1)
      ;; (tooltip-mode -1)           ; Disable tooltips
      ;; Always use spaces for indentation
      (setq-default indent-tabs-mode nil
                    tab-width zamlz/indent-width
                    fill-column zamlz/default-screen-width))
    
  2. Modernize Selection Behaviour

    Replaces active region just by typing text.

    (setq delete-selection-mode +1)
    
  3. Disable Scroll-Bar

    Better scrolling experience

    (setq scroll-margin 0)
    (setq scroll-conservatively 101) ; > 100
    (setq scroll-preserve-screen-position t)
    (setq auto-window-vscroll nil)
    

    Don't display the scroll bar in buffers

    (scroll-bar-mode -1)
    
  4. Enable Column Numbers
    (column-number-mode +1)
    (global-display-line-numbers-mode t)
    

    Don't display line numbers in certain modes

    (dolist (mode '(org-mode-hook
                    term-mode-hook
                    shell-mode-hook
                    eshell-mode-hook
                    vterm-mode-hook))
      (add-hook mode (lambda () (display-line-numbers-mode 0))))
    
  5. Split and Follow Windows
    (defun zamlz/split-and-follow-horizontally ()
      "Split window below."
      (interactive)
      (split-window-below)
      (other-window 1))
    
    (defun zamlz/split-and-follow-vertically ()
      "Split window right."
      (interactive)
      (split-window-right)
      (other-window 1))
    
    (global-set-key (kbd "C-x 2") #'zamlz/split-and-follow-horizontally)
    (global-set-key (kbd "C-x 3") #'zamlz/split-and-follow-vertically)
    
  6. Backup and Autosave Files

    Emacs decides to save backup files and lockfiles within the same directory as the files we are editing. Thats just ugly when looking at the filesystem. This will fix that.

    (setq create-lockfiles nil) ; don't create .# files (crashes 'npm start')
    (setq backup-directory-alist `(("." . "~/.config/emacs/backup")))
    
  7. Eldoc Documentation

    Slightly shorten the Eldoc display delay

    (setq eldoc-idle-delay 0.4)
    
  8. Mouse Wheel Scroll Speed
    (setq mouse-wheel-scroll-amount '(2 ((shift) . 1)))
    (setq mouse-wheel-progressive-speed nil)
    
  9. Highlight Matching Parentheses
    (setq show-paren-delay 0)
    (show-paren-mode +1)
    
  10. Clean Whitespace on Buffer Save
    (use-package whitespace
      :hook (before-save . whitespace-cleanup))
    
  11. Dump Custom-Set-Variables
    (setq custom-file (concat user-emacs-directory "to-be-dumped.el"))
    
  12. Easy PGP Assistant (EPA)

    EPA is a built-in emacs package for interfacing with GnuPG.

    Don't ask by default which key to use

    (setq epa-file-select-keys nil)
    

    Default to user mail address

    (setq epa-file-encrypt-to user-mail-address)
    

    Set the pinentry mode to be loopback to gpg gets the password through emacs instead of using pinentry.

    (setq epa-pinentry-mode 'loopback)
    
  13. Auth Source Pass

    The auth-source-pass package, formerly known as auth-password-store, integrates Emacs' auth-source library with password-store. The auth-source library is a way for Emacs to answer the old burning question “What are my user name and password?”. Password-store (or just pass) is a standard unix password manager following the Unix philosophy. More details can be found at github:DamienCassou/auth-source-pass.

    (use-package auth-source-pass
      :init (auth-source-pass-enable))
    
  14. Calc
    (use-package calc
      :custom
      (calc-angle-mode 'rad)
      (calc-symbolic-mode t))
    

4.5. Interface (Reorganize This)

4.5.1. Font Configuration

;; (defun zamlz/set-font-faces ()
;;   (interactive)
;;   ;; Set default and fixed pitch face
;;   (dolist (face '(default fixed-pitch))
;;     (set-face-attribute `,face nil :font "Iosevka Term" :height 120))
;;   ;; Set the variable pitch face
;;   (set-face-attribute 'variable-pitch nil :font "Arial" :height 120))

Going to copy the font setup that hrs's emacs config has for font configuration. We start by setting the default fixed font and setting it for the default and fixed-pitch faces.

(setq zamlz/default-fixed-font "Iosevka Term")
(setq zamlz/default-fixed-font-size 120)
(setq zamlz/current-fixed-font-size zamlz/default-fixed-font-size)

(set-face-attribute 'default nil
                    :family zamlz/default-fixed-font
                    :height zamlz/current-fixed-font-size)
(set-face-attribute 'fixed-pitch nil
                    :family zamlz/default-fixed-font
                    :height zamlz/current-fixed-font-size)

Next, we do the same procedure for the variable width font

(setq zamlz/default-variable-font "Libre Baskerville")
(setq zamlz/default-variable-font-size 120)
(setq zamlz/current-variable-font-size zamlz/default-variable-font-size)

(set-face-attribute 'variable-pitch nil
                    :family zamlz/default-variable-font
                    :height zamlz/current-variable-font-size)

With this setup, we can define a set of functions that we will use to update the font size.

(setq zamlz/font-change-increment 1.1)

(defun zamlz/set-font-size ()
  "Change default, fixed-pitch, and variable-pitch font sizes to match respective variables."
  (set-face-attribute 'default nil
                      :height zamlz/current-fixed-font-size)
  (set-face-attribute 'fixed-pitch nil
                      :height zamlz/current-fixed-font-size)
  (set-face-attribute 'variable-pitch nil
                      :height zamlz/current-variable-font-size))

(defun zamlz/reset-font-size ()
  "Revert font sizes back to defaults."
  (interactive)
  (setq zamlz/current-fixed-font-size zamlz/default-fixed-font-size)
  (setq zamlz/current-variable-font-size zamlz/default-variable-font-size)
  (zamlz/set-font-size))

(defun zamlz/increase-font-size ()
  "Increase current font sizes by a factor of `zamlz/font-change-increment'."
  (interactive)
  (setq zamlz/current-fixed-font-size
        (ceiling (* zamlz/current-fixed-font-size zamlz/font-change-increment)))
  (setq zamlz/current-variable-font-size
        (ceiling (* zamlz/current-variable-font-size zamlz/font-change-increment)))
  (zamlz/set-font-size))

(defun zamlz/decrease-font-size ()
  "Decrease current font sizes by a factor of `zamlz/font-change-increment', down to a minimum size of 1."
  (interactive)
  (setq zamlz/current-fixed-font-size
        (max 1
             (floor (/ zamlz/current-fixed-font-size zamlz/font-change-increment))))
  (setq zamlz/current-variable-font-size
        (max 1
             (floor (/ zamlz/current-variable-font-size zamlz/font-change-increment))))
  (zamlz/set-font-size))

4.5.2. Themes and Appearance

  1. Highlight Numbers
    (use-package highlight-numbers
      :hook (prog-mode . highlight-numbers-mode))
    
  2. Highlight Escape Sequences
    (use-package highlight-escape-sequences
      :hook (prog-mode . hes-mode))
    
  3. Rainbow Mode
    (use-package rainbow-mode
      :init (rainbow-mode))
    
  4. Transparency
    ;; Set transparency of emacs
    (defun zamlz/set-transparency (value)
      "Sets the transparency of the frame window. 0=transparent/100=opaque"
      (interactive "nTransparency Value 0 - 100 opaque:")
      (set-frame-parameter (selected-frame) 'alpha value))
    
    ;; Add the transparency function to my leader keys
    (require 'init-general)
    (zamlz/leader-keys
      "tx" '(zamlz/set-transparency :which-key "Set transparency"))
    
    ;; Set the default transparency
    (zamlz/set-transparency 100)
    

4.5.3. Daemon and Client Hooks

(if (daemonp)
    (add-hook 'after-make-frame-functions
              (lambda (frame)
                (setq doom-modeline-icon t)
                (with-selected-frame frame
                  (zamlz/reset-font-size)
                  (zamlz/set-transparency 95))))
  (zamlz/reset-font-size))

4.6. Configure System

Before we do anything to crazy, lets load up some system specific settings. Usually this should just contain variable definitions used for other packages to use. Also the contents of this file could be any system file. Currently there are only two being managed right now (Andromeda and Sagittarius).

(require 'init-system)

4.7. Setup Org-mode

We should also make sure to load up Org-mode first. This is vital because we don't want any internal package to accidentally load in built-in version.

(require 'init-org)

4.8. Load Remaining Modules

Let us import the rest of the modules in whatever order we want.

(dolist
    (dir (directory-files (expand-file-name "lisp" user-emacs-directory) nil ".*\\.el"))
  (require (intern (replace-regexp-in-string "\\.el" "" dir))))

4.9. Post Module Configuration

At this point all our modules have been loaded, but there are some settings that we may wish to configure once everything is done loading.

4.9.1. Load Theme

We want to select one of the many themes I may have installed here. List of installed themes:

;; (load-theme 'gruvbox-black t)
;; (load-theme 'doom-old-hope t)
;; (load-theme 'doom-nord t)
(load-theme 'doom-tomorrow-night t)
;; (modus-themes-load-vivendi)

4.9.2. Notetaking Hydra

Let's define a Major Mode Hydra for accessing all notetaking related functions in packages like Org-roam and BibTeX Actions. We don't need to worry about setting up the dependencies as they will be setup at some point, hydra will automatically find them when the function is run.

(pretty-hydra-define zamlz/hydra-notes
  (:title "Notetaking Commands" :color blue :quit-key "q" :exit t)
  (
   "Org Roam"
   (("l" org-roam-buffer-toggle "Toggle Roam Buffer")
    ("/" org-roam-node-find "Find Node")
    ("?" org-roam-ref-find "Find Reference")
    ("i" org-roam-node-insert "Insert Node")
    ("I" org-id-get-create "Create node ID"))
   "Metadata"
   (("t" org-roam-tag-add "Tag Add")
    ("T" org-roam-tag-remove "Tag Remove")
    ("a" org-roam-alias-add "Alias Add")
    ("A" org-roam-alias-remove "Alias Remove")
    ("r" org-roam-ref-add "Reference Add")
    ("R" org-roam-ref-remove "Reference Remove"))
   "BibTeX"
   (("b" bibtex-actions-open "Library")
    ("n" bibtex-actions-open-notes "Notes")
    ("p" bibtex-actions-open-pdf "PDF")
    ("L" bibtex-actions-open-link "Open Link")
    ("e" bibtex-actions-open-entry "View Entry"))
   "Journal"
   ()
   "Misc"
   (("P" zamlz/org-toggle-properties "Toggle Properties Drawer")
    ("d" org-roam-db-sync " DB Sync")
    ("!" zamlz/notetaking-system-refresh "Full Refresh"))))

Add the notetaking Major Mode Hydra to General Leader Keybindings Definer.

(zamlz/leader-keys
  "n" 'zamlz/hydra-notes/body)

We also create a single function that will refresh all parts of our notetaking system.

(defun zamlz/notetaking-system-refresh()
  "Refreshes Org-Roam and Bibtex-Actions"
  (interactive)
  (org-roam-db-sync)
  (bibtex-actions-refresh))

4.9.3. Documentation & Help Hydra

Create a Major Mode Hydra for accessing all help documentation super easily and also provide bindings for packages like Helpful.

(pretty-hydra-define zamlz/hydra-documentation
  (:title "Help & Documentation Commands" :color green :quit-key "q" :exit t)
  ("CMDs/Funcs/Macros"
   (("h" helpful-callable "[ALL]")
    ("c" helpful-command "Command")
    ("f" helpful-function "Function")
    ("m" helpful-macro "Macro"))
  "Variable"
   (("v" helpful-variable "Variable")
    ("V" set-variable "Set Variable")
    ("s" helpful-at-point "Symbol at Point"))
  "Keybindings"
   (("k" helpful-key "Describe Key")
    ("b" embark-bindings "List Bindings"))
   "Documentation"
   (("w" woman "woman"))
   ))

Add the documentation & help Major Mode Hydra to General Leader Keybindings Definer.

(zamlz/leader-keys
  "h" 'zamlz/hydra-documentation/body)

5. Summon the Daemon

Very Important! Make sure we start the emacs daemon here! But do not start it if it's already running. Add this to the xinit user-level scripts.

if [ -z "$(pgrep -f 'emacs --daemon=xorg-emacs-daemon')" ]; then
    emacs --daemon=xorg-emacs-daemon
fi

6. Xresources Setup

The colorscheme defined in Xresources below doesn't actually matter. Emacs will override it anyway when you load our actual colorscheme. However, Emacs does in fact load this before rendering the GUI Window where as our actual colorscheme is loaded after the GUI Window is drawn. Therefore, this simple setup prevents the blinding white flash from appearing at startup! Secondly, if the Emacs config is bricked for some reason, our barebones environment will still be in dark mode.

emacs*foreground: xforeground
emacs*background: xbackground

emacs*color0:  xcolor0
emacs*color1:  xcolor1
emacs*color2:  xcolor2
emacs*color3:  xcolor3
emacs*color4:  xcolor4
emacs*color5:  xcolor5
emacs*color6:  xcolor6
emacs*color7:  xcolor7
emacs*color8:  xcolor8
emacs*color9:  xcolor9
emacs*color10: xcolor10
emacs*color11: xcolor11
emacs*color12: xcolor12
emacs*color13: xcolor13
emacs*color14: xcolor14
emacs*color15: xcolor15

Created: 2021-11-13

Emacs 26.1 (Org mode 9.5)