Skip to content

Files

Latest commit

 

History

History
2613 lines (2354 loc) · 94.3 KB

PostInitConfig.org

File metadata and controls

2613 lines (2354 loc) · 94.3 KB

Post Init Emacs Configuration

Table of Contents

Introduction

This config is built by copying parts from System Crafters dotfiles repo, what I found on the internet (Reddit, Discord, Stack Overflow, etc.) and some of my own config. This configuration is based on the literate programming paradigm which makes the config be self-documenting. This means, the file is basically a fully explained documentation of my config and also contains code blocks in between that can be evaluated and tangled into a config file.

Personal Information

It’s useful to set up personal information. Some packages tend to use it.

;;; private-config.el --- DESCRIPTION -*- lexical-binding: t; -*- 
(setq user-full-name "Rajath Ramakrishna"
      user-mail-address "[email protected]")

I’ve been using Emacs since Aug 2020. I used Spacemacs briefly for about a month and it was slow, clunky and I didn’t have a good workflow for editing org files on my phone. I decided to give Emacs another go and used Doom Emacs since it looked prettier and I instantly fell in love with it. I used Doom Emacs for about a year and some time late August 2021 is when I started building my own config.

If this is the first time you are looking at my configuration, feel free to jump around and look at any code blocks. Headings that are marked with TODO need some work. They either have configs that are not completely set up or have tangling disabled, or just need some text.

Why literate config?

Literate config has a few benefits:

  • Easy to understand. Thanks to the documentation surrounding the code snippets
  • Easy to share. People you share this with need no explanation as to what’s in your config, your documentation takes care of that
  • Easy to maintain. You never touch the actual config, you only update this .org file and make it generate the actual source file
  • Easy to publish. If you want to publish your config online, it’s super easy. GitHub, for example, natively supports org the same way it supports Markdown. So, these org files are rendered nicely, just as regular documentation.

First things first

Set lexical binding

This sets lexical binding to true

;;; post-init.el --- DESCRIPTION -*- no-byte-compile: t; lexical-binding: t; -*-

Startup Performance

;;  (setq gc-cons-threshold (* 50 1000 1000))

(defun rr/display-startup-time ()
  "Displays startup time in the echo buffer and Messages buffer as
    soon as Emacs loads."
  (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 #'rr/display-startup-time)

Start emacs in server mode

(server-start)

Keep .emacs.d clean

This is to avoid emacs from creating temporary files: Package: no-littering

(use-package no-littering)

(setq auto-save-file-name-transforms
      `((".*" ,(no-littering-expand-var-file-name "auto-save/") t)))

(setq custom-file (expand-file-name "custom.el" user-emacs-directory))

Use straight-use-package org

(straight-use-package 'org)

Set variables

This section sets variables found in .envrc in order to use them later on in the config. This is useful for configs that are shared across multiple machines but have different values. For example, org-mode directory may be at different locations in two different machines. Reading the path from an envrc file makes the config cleaner and easier to maintain and all the necessary paths and values can be offloaded to a different file (envrc)

(direnv-allow)
(setq rr-org-mode-dir (getenv "ORG_MODE_DIR"))
(setq rr-org-roam-dir (getenv "ORG_ROAM_DIR"))
(setq pplx-api-key (getenv "PPLX_API_KEY"))
(setq initial-major-mode #'lisp-interaction-mode)

UI Configuration

Set up fonts

This font face will be used everywhere in Emacs, not just in source code

(setq my-fixed-pitch-font "JetBrains Mono")
(setq my-variable-pitch-font "SN Pro")

(defun rr/set-font-faces ()
  (message "Setting font faces!")
  (set-face-attribute 'default nil :font "JetBrains Mono" :height 125)
  ;; Set the fixed pitch face
  (set-face-attribute 'fixed-pitch nil
                      :font my-fixed-pitch-font
                      :height 170
                      :weight 'light)

  ;; Set the variable pitch face
  (set-face-attribute 'variable-pitch nil
                      :font my-variable-pitch-font
                      :height 150
                      :weight 'regular))

(if (daemonp)
    (add-hook 'after-make-frame-functions
              (lambda (frame)
                (setq doom-modeline-icon t)
                (with-selected-frame frame (rr/set-font-faces))))
  (rr/set-font-faces))

Set up icons

Package: nerd-icons

Using nerd icons package to make the modeline look pretty.

(use-package nerd-icons
  :vc (:url "https://github.com/rainstormstudio/nerd-icons.el")
  :custom
  (set-fontset-font t 'symbol "Symbols Nerd Font Mono" nil 'prepend)
  (nerd-icons-font-family "Symbols Nerd Font Mono")
  (nerd-icons-scale-factor 1.15))

Set up theme

I use the Doom-One theme with a Doom modeline and also use all-the-icons for pretty icons. The following code block sets them up Packages:

(use-package doom-modeline
  :after nerd-icons
  :init (doom-modeline-mode 1)
  :custom
  (doom-modeline-height 30))

(use-package doom-themes
  :config
  (setq doom-themes-enable-bold t    ; if nil, bold is universally disabled
        doom-themes-enable-italic t) ; if nil, italics is universally disabled
  (load-theme 'doom-molokai t)

  ;; Enable flashing mode-line on errors
  (doom-themes-visual-bell-config)
  ;; Enable custom neotree theme
  ;; (doom-themes-neotree-config)
  (doom-themes-org-config))

(use-package all-the-icons)

;; Set modeline's background to something lighter
(set-face-attribute 'mode-line nil
                    :background "#2c323b")

;; Make the titlebar on MacOS transparent
(add-to-list 'default-frame-alist '(ns-transparent-titlebar . t))

Rainbow Delimiters

Lisp stands for Lots of Irritating Superfluous Parentheses. Let’s make them colorful at least. Package: rainbow-delimiters

(use-package rainbow-delimiters
  :defer t
  :hook (prog-mode . rainbow-delimiters-mode))

Usability

Auto-saving changed files

This removes the need to hit Save all the time.

(defun rr/auto-save-on-idle ()
  "Auto-save current buffer if it's file-visiting and modified."
  (when (and buffer-file-name
             (buffer-modified-p)
             (file-writable-p buffer-file-name))
    (save-buffer)))

(run-with-idle-timer 3 t #'rr/auto-save-on-idle)

(setq backup-directory-alist
      `((".*" . ,temporary-file-directory)))
(setq auto-save-file-name-transforms
      `((".*" ,temporary-file-directory t)))

Jumping around with Avy

Jump to any character, word or line in the visible region. Keybindings for this are described under Keybindings/General configuration. Package: avy

(use-package avy
  :commands (avy-goto-char avy-goto-word-0 avy-goto-line))

Hungry Delete

If there are multiple consecutive whitespaces, I don’t want to repeatedly hit delete to remove all the whitespaces. Instead, I just want to hit it once. Package: hungry-delete

(use-package hungry-delete
  :defer 2
  :config
  (setq hungry-delete-join-reluctantly t))
(global-hungry-delete-mode)

Revert buffer NOCONFIRM

I keep having to revert buffer for different reasons and when I hit the command, it asks me for confirmation. I don’t want to say yes every single time.

(defun rr/revert-buffer-no-confirm ()
  "Revert the buffer, but don't ask for confirmation"
  (interactive)
  (revert-buffer nil t nil))

Insert HTML link with title as default description

Taken from: https://orgmode.org/worg/org-hacks.html#org4f1a640

(require 'mm-url) ; to include mm-url-decode-entities-string

(defun rr/org-insert-html-link ()
  "Insert org link where default description is set to html title."
  (interactive)
  (let* ((url (read-string "URL: "))
         (title (rr/get-html-title-from-url url)))
    (org-insert-link nil url title)))

(defun rr/get-html-title-from-url (url)
  "Return content in <title> tag."
  (let (x1 x2 (download-buffer (url-retrieve-synchronously url)))
    (save-excursion
      (set-buffer download-buffer)
      (beginning-of-buffer)
      (setq x1 (search-forward "<title>"))
      (search-forward "</title>")
      (setq x2 (search-backward "<"))
      (mm-url-decode-entities-string (buffer-substring-no-properties x1 x2)))))

Highlight Symbol

(use-package highlight-symbol
  :config
  (set-face-attribute 'highlight-symbol-face nil
                      :background (face-background 'default)
                      :foreground "#48E5C2") ;original: #FA009A, DE7C5A
  (setq highlight-symbol-idle-delay 0)
  (setq highlight-symbol-on-navigation-p t)
  (add-hook 'prog-mode-hook #'highlight-symbol-mode)
  (add-hook 'prog-mode-hook #'highlight-symbol-nav-mode))

Embark

Package: Embark

(use-package embark
  :ensure t

  :bind
  (("C-," . embark-act)         ;; pick some comfortable binding
   ("C-M-," . embark-dwim)        ;; good alternative: M-.
   ("C-h B" . embark-bindings)) ;; alternative for `describe-bindings'

  :init

  ;; Optionally replace the key help with a completing-read interface
  (setq prefix-help-command #'embark-prefix-help-command)

  :config
  (keymap-set minibuffer-local-map "M-k" "C-. k y")
  ;; Hide the mode line of the Embark live/completions buffers
  (add-to-list 'display-buffer-alist
               '("\\`\\*Embark Collect \\(Live\\|Completions\\)\\*"
                 nil
                 (window-parameters (mode-line-format . none)))))

;; Consult users will also want the embark-consult package.
(use-package embark-consult
  :ensure t ; only need to install it, embark loads it after consult if found
  :hook
  (embark-collect-mode . consult-preview-at-point-mode))

Embrace

(use-package embrace
  :defer t)
(global-set-key (kbd "C-.") #'embrace-commander)
(add-hook 'org-mode-hook #'embrace-org-mode-hook)

Pulse Line

Found this in a reddit comment that does the same thing as beacon. Basically flashes the active line on window selction changes.

(defun rr/pulse-line (_)
  (pulse-momentary-highlight-one-line (point)))
(setq window-selection-change-functions '(rr/pulse-line))

Moving Lines

Move line down

(defun rr/move-line-down ()
  (interactive)
  (forward-line 1)
  (transpose-lines 1)
  (forward-line -1))

(global-set-key (kbd "M-<down>") 'rr/move-line-down)

Move line up

(defun rr/move-line-up ()
  (interactive)
  (transpose-lines 1)
  (forward-line -2))

(global-set-key (kbd "M-<up>") 'rr/move-line-up)

Popper

Manage pop up windows with ease. Make specific major modes open as popups. Package: popper

(use-package popper
  :init
  (setq popper-reference-buffers
        '("\\*Messages\\*"
          "^\\*Warnings\\*"
          "^\\*IBuffer\\*"
          "^\\*Compile-Log\\*"
          "^\\*Backtrace\\*"
          "[Oo]utput\\*$"
          "\\*Help\\*"
          "\\*helpful\\*"
          "\\*Excorporate\\*"
          "\\*xref\\*"
          eat-mode
          help-mode
          helpful-mode
          compilation-mode
          org-roam-mode
          term-mode))
  (popper-mode +1))

Golden Ratio

Package: golden-ratio

(use-package golden-ratio
  :ensure t
  :config
  (golden-ratio-mode 1)
  (setq golden-ratio-auto-scale t))

Other minor settings

(setq which-key-idle-delay 0.3)
(setq which-key-max-description-length 100)
(global-visual-line-mode)
(pixel-scroll-precision-mode)

Keybindings

Switch buffers easily

consult-buffer lets you preview buffers as you scroll through them. It is not set to the keybinding C-M-j for easy access. Also, these buffers are aggregated across workspaces (or perspectives).

(global-set-key (kbd "C-M-j") 'consult-buffer)

Global keys

I constantly hit C-w to delete words and currently it’s bound to delete region, which deletes a huge chunk of text. This keybinding will give a better experience in deleting words.

(keymap-global-set "C-w" 'backward-kill-word)
(keymap-global-set "C-s" 'save-buffer)
(keymap-global-set "s-[" 'tab-previous)
(keymap-global-set "s-]" 'tab-next)
(keymap-global-set "s-r" 'rr/revert-buffer-no-confirm)
(keymap-global-set "M-o" 'completion-at-point)
(keymap-global-set "C-S-u" 'universal-argument)

Meow

Custom Functions

This section has all the custom functions I use for Meow Mode. Most of them are written to make it work like Helix.

Meow Insert at start

This function upon execution moves the cursor to the beginning of the line and turns on the insert mode

(defun rr/meow-insert-at-start ()
  (interactive)
  (beginning-of-line)
  (meow-insert-mode))

Meow Insert at end

This function upon execution moves the cursor to the end of the line and turns on the insert mode

(defun rr/meow-insert-at-end ()
  (interactive)
  (end-of-line)
  (meow-insert-mode))

Meow Paste before

Pastes whatever is in the clipboard on the line above the cursor’s current position.

(defun rr/meow-paste-before ()
  (interactive)
  (meow-open-above)
  (beginning-of-line)
  (meow-yank)
  (meow-normal-mode))

Meow delete char or region

Deletes char if no region is selected. Deletes region if selected. Cuts org subtree if point is on an org heading

(defun rr/meow-delete-char-or-region ()
  (interactive)
  (cond
   ((equal mark-active t)
    (if (org-at-heading-p)
        (org-cut-subtree)
      (delete-region (region-beginning) (region-end))))
   ((equal mark-active nil)
    (delete-char 1))))

Meow Save

Copies the entire line when no selection exists Copies region when there’s selection Copies org subtree if point is on an org heading

(defun rr/copy-line ()
  (interactive)
  (save-excursion
    (back-to-indentation)
    (kill-ring-save
     (point)
     (line-end-position)))
  (message "1 line copied"))

(defun rr/meow-save ()
  (interactive)
  (cond
   ((org-at-heading-p)
    (org-copy-subtree))
   ((equal mark-active t)
    (meow-save))
   ((equal mark-active nil)
    (rr/copy-line))))

Custom Keymaps

Nav Keymap

This keymap is used for navigation. A lot of the functions here try to emulate Helix keybindings and navigation in order to make the experience more consistent.

(defvar meow-nav-keymap
  (let ((keymap (make-keymap)))
    (define-key keymap (kbd "h") #'beginning-of-line)
    (define-key keymap (kbd "l") #'end-of-line)
    (define-key keymap (kbd "g") #'beginning-of-buffer)
    (define-key keymap (kbd "e") #'end-of-buffer)
    (define-key keymap (kbd "s") #'back-to-indentation)
    (define-key keymap (kbd "y") #'eglot-find-typeDefinition)
    (define-key keymap (kbd "i") #'eglot-find-implementation)
    keymap))

;; define an alias for your keymap
(defalias 'meow-nav-keymap meow-nav-keymap)
;;  (global-set-key (kbd "C-x C-w") 'nav-keymap)
;;                              ^ note the quote

Persp keymap

(defvar meow-persp-keymap
  (let ((keymap (make-keymap)))
    (define-key keymap (kbd "s") #'persp-switch)
    (define-key keymap (kbd "b") #'persp-switch-to-buffer)
    (define-key keymap (kbd "k") #'persp-kill)
    (define-key keymap (kbd "r") #'persp-rename)
    keymap))

;; define an alias for your keymap
(defalias 'meow-persp-keymap meow-persp-keymap)

Buffer Keymap

(defvar meow-buffer-keymap
  (let ((keymap (make-keymap)))
    (define-key keymap (kbd "k") #'kill-buffer)
    (define-key keymap (kbd "r") #'rr/revert-buffer-no-confirm)
    (define-key keymap (kbd "R") #'revert-buffer)
    (define-key keymap (kbd "i") #'ibuffer)
    (define-key keymap (kbd "o") #'centaur-tabs-kill-other-buffers-in-current-group)
    keymap))

;; define an alias for your keymap
(defalias 'meow-buffer-keymap meow-buffer-keymap)

Help Keymap

(defvar meow-help-keymap
  (let ((keymap (make-keymap)))
    (define-key keymap (kbd "f") #'describe-function)
    (define-key keymap (kbd "v") #'describe-variable)
    (define-key keymap (kbd "c") #'describe-key-briefly)
    (define-key keymap (kbd "a") #'apropos-command)
    (define-key keymap (kbd "b") #'describe-bindings)
    keymap))

;; define an alias for your keymap
(defalias 'meow-help-keymap meow-help-keymap)

Dired Keymap

(defvar meow-dired-keymap
  (let ((keymap (make-keymap)))
    (define-key keymap (kbd "d") #'dired)
    (define-key keymap (kbd "j") #'dired-jump)
    (define-key keymap (kbd "J") #'dired-jump-other-window)
    (define-key keymap (kbd "n") #'dired-create-empty-file)
    keymap))

;; define an alias for your keymap
(defalias 'meow-dired-keymap meow-dired-keymap)

Window Keymap

(defvar meow-window-keymap
  (let ((keymap (make-keymap)))
    (define-key keymap (kbd "v") #'split-window-right)
    (define-key keymap (kbd "h") #'split-window-below)
    (define-key keymap (kbd "c") #'delete-window)
    (define-key keymap (kbd "w") #'next-window-any-frame)
    keymap))

;; define an alias for your keymap
(defalias 'meow-window-keymap meow-window-keymap)

File Keymap

(defvar meow-file-keymap
  (let ((keymap (make-keymap)))
    (define-key keymap (kbd "f") #'find-file)
    (define-key keymap (kbd "r") #'consult-recent-file)
    (define-key keymap (kbd "p") #'projectile-find-file)
    keymap))

;; define an alias for your keymap
(defalias 'meow-file-keymap meow-file-keymap)

Org Keymaps

Org checklist keymap
(defvar meow-org-checklist-keymap
  (let ((keymap (make-keymap)))
    (define-key keymap (kbd "x") #'org-toggle-checkbox)
    (define-key keymap (kbd "s") #'rr/org-sort-list-by-checkbox-type)
    (define-key keymap (kbd "S") #'org-sort)
    keymap))

;; define an alias for your keymap
(defalias 'meow-org-checklist-keymap meow-org-checklist-keymap)
Org clock keymap
(defvar meow-org-clock-keymap
  (let ((keymap (make-keymap)))
    (define-key keymap (kbd "i") #'org-clock-in)
    (define-key keymap (kbd "o") #'org-clock-out)
    (define-key keymap (kbd "c") #'org-clock-cancel)
    (define-key keymap (kbd "d") #'org-clock-display)
    (define-key keymap (kbd "g") #'org-clock-goto)
    keymap))

;; define an alias for your keymap
(defalias 'meow-org-clock-keymap meow-org-clock-keymap)
Org narrow keymap
(defvar meow-org-narrow-keymap
  (let ((keymap (make-keymap)))
    (define-key keymap (kbd "s") #'org-narrow-to-subtree)
    (define-key keymap (kbd "b") #'org-narrow-to-block)
    (define-key keymap (kbd "e") #'org-narrow-to-element)
    (define-key keymap (kbd "r") #'org-narrow-to-region)
    (define-key keymap (kbd "w") #'widen)
    keymap))

;; define an alias for your keymap
(defalias 'meow-org-narrow-keymap meow-org-narrow-keymap)
Org deadline keymap
(defvar meow-org-deadline-keymap
  (let ((keymap (make-keymap)))
    (define-key keymap (kbd "s") #'org-schedule)
    (define-key keymap (kbd "d") #'org-deadline)
    (define-key keymap (kbd "t") #'org-time-stamp)
    (define-key keymap (kbd "T") #'org-time-stamp-inactive)
    keymap))

;; define an alias for your keymap
(defalias 'meow-org-deadline-keymap meow-org-deadline-keymap)
Org link keymap
(defvar meow-org-link-keymap
  (let ((keymap (make-keymap)))
    (define-key keymap (kbd "l") #'org-insert-link)
    (define-key keymap (kbd "v") #'crux-view-url)
    (define-key keymap (kbd "s") #'org-store-link)
    (define-key keymap (kbd "h") #'rr/org-insert-html-link)
    (define-key keymap (kbd "d") #'rr/org-insert-link-dwim)
    keymap))

;; define an alias for your keymap
(defalias 'meow-org-link-keymap meow-org-link-keymap)
Org toggle keymap
(defvar meow-org-toggle-keymap
  (let ((keymap (make-keymap)))
    (define-key keymap (kbd "h") #'org-toggle-heading)
    (define-key keymap (kbd "i") #'org-toggle-item)
    (define-key keymap (kbd "x") #'org-toggle-checkbox)
    keymap))

;; define an alias for your keymap
(defalias 'meow-org-toggle-keymap meow-org-toggle-keymap)
Org refile keymap
(defvar meow-org-refile-keymap
  (let ((keymap (make-keymap)))
    (define-key keymap (kbd "r") #'org-refile)
    (define-key keymap (kbd "c") #'org-refile-copy)
    (define-key keymap (kbd ".") #'+org/refile-to-current-file)
    (define-key keymap (kbd "A") #'org-archive-subtree)
    keymap))

;; define an alias for your keymap
(defalias 'meow-org-refile-keymap meow-org-refile-keymap)
Org main keymap
(defvar meow-org-keymap
  (let ((keymap (make-keymap)))
    (define-key keymap (kbd "x") #'meow-org-checklist-keymap)
    (define-key keymap (kbd "c") #'meow-org-clock-keymap)
    (define-key keymap (kbd "r") #'meow-org-refile-keymap)
    (define-key keymap (kbd "n") #'meow-org-narrow-keymap)
    (define-key keymap (kbd "d") #'meow-org-deadline-keymap)
    (define-key keymap (kbd "l") #'meow-org-link-keymap)
    (define-key keymap (kbd "t") #'meow-org-toggle-keymap)
    (define-key keymap (kbd "N") #'org-add-note)
    (define-key keymap (kbd "o") #'consult-outline)
    (define-key keymap (kbd "q") #'org-set-tags-command)
    (define-key keymap (kbd "e") #'org-export-dispatch)
    (define-key keymap (kbd "a") #'org-agenda)
    keymap))

;; define an alias for your keymap
(defalias 'meow-org-keymap meow-org-keymap)

Avy Keymap

(defvar meow-avy-keymap
  (let ((keymap (make-keymap)))
    (define-key keymap (kbd "j") #'avy-goto-char)
    (define-key keymap (kbd "w") #'avy-goto-word-1)
    (define-key keymap (kbd "l") #'avy-goto-line)
    keymap))

;; define an alias for your keymap
(defalias 'meow-avy-keymap meow-avy-keymap)

Project Keymap

(defvar meow-project-keymap
  (let ((keymap (make-keymap)))
    (define-key keymap (kbd "f") #'consult-project-extra-find)
    (define-key keymap (kbd "D") #'project-find-dir)
    (define-key keymap (kbd "d") #'project-dired)
    (define-key keymap (kbd "m") #'magit-project-status)
    (define-key keymap (kbd "k") #'project-kill-buffers)
    (define-key keymap (kbd "s") #'project-switch-project)
    (define-key keymap (kbd "c") #'consult-project-buffer)
    (define-key keymap (kbd "/") #'consult-ripgrep)
    (define-key keymap (kbd "t") #'eat-project-other-window)
    keymap))

;; define an alias for your keymap
(defalias 'meow-project-keymap meow-project-keymap)

Eglot/Flymake Keymap

(defvar meow-eglot-keymap
  (let ((keymap (make-keymap)))
    (define-key keymap (kbd "a") #'eglot-code-actions)
    (define-key keymap (kbd "f") #'project-find-file)
    (define-key keymap (kbd "n") #'flymake-goto-next-error)
    (define-key keymap (kbd "p") #'flymake-goto-prev-error)
    (define-key keymap (kbd "s") #'flymake-show-project-diagnostics)
    (define-key keymap (kbd "r") #'eglot-rename)
    (define-key keymap (kbd "R") #'eglot-reconnect)
    (define-key keymap (kbd "c") #'consult-flymake)
    (define-key keymap (kbd ">") #'diff-hl-next-hunk)
    (define-key keymap (kbd "<") #'diff-hl-previous-hunk)
    keymap))

;; define an alias for your keymap
(defalias 'meow-eglot-keymap meow-eglot-keymap)

Utilities

Highlight Symbol Keymap
(defvar meow-highlight-keymap
  (let ((keymap (make-keymap)))
    (define-key keymap (kbd "t") #'highlight-symbol-mode)
    (define-key keymap (kbd "n") #'highlight-symbol-next)
    (define-key keymap (kbd "p") #'highlight-symbol-prev)
    (define-key keymap (kbd "r") #'highlight-symbol-remove-all)
    (define-key keymap (kbd "c") #'highlight-symbol-count)
    keymap))

;; define an alias for your keymap
(defalias 'meow-highlight-keymap meow-highlight-keymap)
Util Keymap
(defvar meow-util-keymap
  (let ((keymap (make-keymap)))
    (define-key keymap (kbd "r") #'restart-emacs)
    (define-key keymap (kbd "h") #'meow-highlight-keymap)
    (define-key keymap (kbd "g") #'magit-status)
    (define-key keymap (kbd "G") #'git-link)
    (define-key keymap (kbd "k") #'magit-discard)
    (define-key keymap (kbd "f") #'free-keys)
    (define-key keymap (kbd "w") #'writegood-mode)
    (define-key keymap (kbd "p") #'popper-toggle)
    (define-key keymap (kbd "l") #'consult-goto-line)
    keymap))

;; define an alias for your keymap
(defalias 'meow-util-keymap meow-util-keymap)

Meow Setup

This has key mappings to a bunch of things. It is the main entry point to do most of the operations. Space is the leader key and I’m trying to keep it consistent with the keymap I had with General.

(defun meow-setup ()
  (setq meow-cheatsheet-layout meow-cheatsheet-layout-qwerty)
  (meow-motion-overwrite-define-key
   '("j" . meow-next)
   '("k" . meow-prev)
   '("<escape>" . ignore))
  (meow-leader-define-key
   ;; SPC j/k will run the original command in MOTION state.
   '("j" . "H-j")
   '("k" . "H-k")
   ;; Use SPC (0-9) for digit arguments.
   '("1" . meow-digit-argument)
   '("2" . meow-digit-argument)
   '("3" . meow-digit-argument)
   '("4" . meow-digit-argument)
   '("5" . meow-digit-argument)
   '("6" . meow-digit-argument)
   '("7" . meow-digit-argument)
   '("8" . meow-digit-argument)
   '("9" . meow-digit-argument)
   '("0" . meow-digit-argument)
   '("`" . meow-last-buffer)
   '("RET" . consult-bookmark)
   '("b" . meow-buffer-keymap)
   '("h" . meow-help-keymap)  
   '("s" . meow-persp-keymap)
   '("d" . meow-dired-keymap)
   '("j" . meow-avy-keymap)
   '("f" . meow-file-keymap)
   '("l" . meow-eglot-keymap)
   '("p" . meow-project-keymap)
   '("u" . meow-util-keymap)
   '("w" . meow-window-keymap)
   '("o" . meow-org-keymap)
   '("/" . meow-keypad-describe-key)
   '("z" . scratch-buffer)
   '("?" . meow-cheatsheet))
  (meow-normal-define-key
   '("0" . meow-expand-0)
   '("9" . meow-expand-9)
   '("8" . meow-expand-8)
   '("7" . meow-expand-7)
   '("6" . meow-expand-6)
   '("5" . meow-expand-5)
   '("4" . meow-expand-4)
   '("3" . meow-expand-3)
   '("2" . meow-expand-2)
   '("1" . meow-expand-1)
   '("-" . negative-argument)
   '(";" . meow-reverse)
   '("," . meow-inner-of-thing)
   '("." . meow-bounds-of-thing)
   '("/" . isearch-forward)
   '("C-;" . popper-kill-latest-popup)
   '("C-S-s" . consult-line)
   '("C-u" . meow-page-up)
   '("C-d" . meow-page-down)
   '("C-w" . backward-kill-word)
   '("RET" . +org/dwim-at-point)
   ;; '("TAB" . +org-cycle-only-current-subtree-h)
   ;; '("C-n" . rr/org-show-next-heading-tidily)
   ;; '("C-p" . rr/org-show-previous-heading-tidily)
   '("t" . org-todo)
   '("[" . meow-beginning-of-thing)
   '("]" . meow-end-of-thing)
   '("a" . meow-append)
   '("A" . rr/meow-insert-at-end)
   '("b" . meow-back-word)
   '("B" . meow-back-symbol)
   '("c" . meow-change)
   '("d" . rr/meow-delete-char-or-region)
   '("D" . meow-backward-delete)
   '("e" . meow-block)
   '("E" . meow-to-block)
   '("f" . meow-find)
   '("F" . eglot-code-actions)
   '("g" . meow-nav-keymap)
   '("G" . meow-grab)
   '("h" . meow-left)
   '("H" . meow-left-expand)
   '("i" . meow-insert)
   '("I" . rr/meow-insert-at-start)
   '("j" . meow-next)
   '("J" . meow-next-expand)
   '("k" . meow-prev)
   '("K" . meow-prev-expand)
   '("l" . meow-right)
   '("L" . meow-right-expand)
   '("m" . meow-mark-word)
   '("M" . meow-mark-symbol)
   '("n" . meow-search)
   '("N" . flymake-goto-next-error)
   '("o" . meow-open-below)
   '("O" . meow-open-above)
   '("p" . meow-yank)
   '("P" . rr/meow-paste-before)
   '("Q" . meow-goto-line)
   '("r" . meow-replace)
   '("R" . meow-swap-grab)
   '("s" . meow-kill)
   '("T" . meow-till)
   '("u" . undo)
   '("U" . undo-redo)
   '("v" . meow-visit)
   '("w" . meow-next-word)
   '("W" . meow-next-symbol)
   '("x" . meow-line)
   '("X" . org-capture)
   '("y" . rr/meow-save)
   '("Y" . meow-sync-grab)
   '("z" . meow-pop-selection)
   '("'" . repeat)
   '(";" . meow-cancel-selection)
   '(":" . meow-reverse)
   '("<escape>" . ignore)))

Meow Package Setup

(use-package meow
  :custom
  (meow-use-cursor-position-hack t)
  (meow-use-clipboard t)
  (meow-goto-line-function 'consult-goto-line)
  :config
  (setq meow--kbd-delete-char "<deletechar>")
  (add-to-list 'meow-char-thing-table '(?a . angle))
  (meow-global-mode 1)
  (meow-setup))

(global-set-key (kbd "C-<tab>") 'meow-last-buffer)

Completion Frameworks

Vertico

Package: vertico

(defun rr/minibuffer-backward-kill (arg)
  "When minibuffer is completing a file name delete up to parent
folder, otherwise delete a word"
  (interactive "p")
  (if minibuffer-completing-file-name
      ;; Borrowed from https://github.com/raxod502/selectrum/issues/498#issuecomment-803283608
      (if (string-match-p "/." (minibuffer-contents))
          (zap-up-to-char (- arg) ?/)
        (delete-minibuffer-contents))
    (delete-word (- arg))))
(use-package vertico
  :defer t
  :bind (:map minibuffer-local-map
              ("<Backspace>" . rr/minibuffer-backward-kill))
  :custom
  (vertico-cycle t)
  :init
  (vertico-mode +1)
  (setq completion-styles '(flex partial-completion)
        completion-ignore-case t
        completion-category-defaults nil
        completion-category-overrides nil))

(define-key vertico-map "?" #'minibuffer-completion-help)
(define-key vertico-map (kbd "M-RET") #'minibuffer-force-complete-and-exit)
(define-key vertico-map (kbd "M-TAB") #'minibuffer-complete)

Marginalia

This package gives nice little extra information in the minibuffer while doing a describe function, describe variable, finding files, etc. Package: marginalia

(use-package marginalia
  :after vertico
  :custom
  (marginalia-annotators '(marginalia-annotators-heavy marginalia-annotators-light nil))
  (marginalia-align 'right)
  (marginalia-align-offset -5)
  :init
  (marginalia-mode))

(use-package all-the-icons-completion
  :after (marginalia all-the-icons)
  :hook (marginalia-mode . all-the-icons-completion-marginalia-setup)
  :init
  (all-the-icons-completion-mode))

Orderless

Package: orderless

(use-package orderless
  :after vertico
  :init
  (setq completion-styles '(orderless)
        completion-category-defaults nil
        completion-category-overrides '((file (styles . (partial-completion))
                                              (minibuffer (initials))))))

Consult

Package: consult

Consult package setup

Sets up some basic hooks, keybindings, theme, etc.

(use-package consult
  :defer t
  :hook (completion-list-mode . consult-preview-at-point-mode)
  :init
  :config
  (consult-customize
   consult-theme
   :preview-key '(:debounce 0.2 any)
   consult-ripgrep consult-git-grep consult-grep
   consult-bookmark consult-recent-file consult-xref
   consult--source-bookmark consult--source-recent-file
   consult--source-project-recent-file
   :preview-key "M-.")
  ;; Optionally configure the narrowing key.
  ;; Both < and C-+ work reasonably well.
  (setq consult-narrow-key "<") ;; (kbd "C-+")
  )

Corfu

Found it here: https://gitlab.com/nathanfurnal/dotemacs/-/blob/master/init.el#L251

(use-package corfu
  :defer t
  :ensure t
  ;; Optional customizations
  :custom
  (corfu-cycle t)                ;; Enable cycling for `corfu-next/previous'
  (corfu-auto t)                 ;; Enable auto completion
  (corfu-separator ?\s)          ;; Orderless field separator
  (corfu-quit-at-boundary 'separator)	;; Never quit at completion boundary
  (corfu-quit-no-match 'separator)      ;; Never quit, even if there is no match
  (corfu-preview-current 'insert)    ;; Disable current candidate preview
  (corfu-preselect-first nil)    ;; Disable candidate preselection
  (corfu-on-exact-match nil)     ;; Configure handling of exact matches
  (corfu-echo-documentation nil) ;; Disable documentation in the echo area
  (corfu-scroll-margin 5)        ;; Use scroll margin

  ;; Enable Corfu only for certain modes.
  :hook ((prog-mode . corfu-mode)
         (shell-mode . corfu-mode)
         (eshell-mode . corfu-mode)
         (typescript-mode . corfu-mode)
         (typescript-ts-mode . corfu-mode))

  ;; Recommended: Enable Corfu globally.
  ;; This is recommended since Dabbrev can be used globally (M-/).
  ;; See also `corfu-excluded-modes'.
  :init
  (global-corfu-mode))

(setq tab-always-indent 'complete)

Kind Icon

Package: kind-icon

(use-package kind-icon
  :after corfu
  :custom
  (kind-icon-use-icons t)
  (kind-icon-default-face 'corfu-default)
  (kind-icon-blend-background nil)
  (kind-icon-blend-frac 0.08)
  (svg-lib-icons-dir (no-littering-expand-var-file-name "svg-lib/cache/"))
  :config
  (add-to-list 'corfu-margin-formatters #'kind-icon-margin-formatter))

Utilities

Helpful package for better documentation formatting

This gives better links and formatting inside emacs documentation. This is particularly helpful while looking up documentation for functions, variables, etc. I have remapped existing describe function to the helpful versions so that I don’t have to specifically invoke helpful commands. Package: helpful

(use-package helpful
  :defer t
  :commands (helpful-callable helpful-variable helpful-command helpful-key helpful-function)
  :bind
  ([remap describe-command] . helpful-command)
  ([remap describe-function] . helpful-callable)
  ([remap describe-variable] . helpful-variable)
  ([remap describe-key] . helpful-key))

Crux

Collection of Really Useful eXtensions Package: crux

(use-package crux
  :defer t)

Free Keys

This package shows a list of unbound keys so that it’s easy to pick one while assigning a keybinding to a function

(use-package free-keys
  :defer t)

Direnv

Package: direnv

(use-package direnv
  :config
  (direnv-mode)
  (direnv-allow))

Dired

File management with dired

(use-package dired
  :demand t
  :ensure nil
  :commands (dired dired-jump)
  :bind (:map dired-mode-map
              ("H" . dired-omit-mode)
              ("h" . dired-single-up-directory)
              ("l" . dired-single-buffer))

  :config
  (setq
   ;; https://github.com/d12frosted/homebrew-emacs-plus/issues/383
   insert-directory-program "/opt/homebrew/bin/gls"
   dired-listing-switches "-tagho --group-directories-first"
   dired-omit-files "^\\.[^.].*"
   dired-omit-verbose nil
   dired-hide-details-hide-symlink-targets nil
   dired-kill-when-opening-new-dired-buffer t
   delete-by-moving-to-trash t)

  (autoload 'dired-omit-mode "dired-x")

  (add-hook 'dired-load-hook
            (lambda ()
              (interactive)
              (dired-collapse)))

  (add-hook 'dired-mode-hook
            (lambda ()
              (interactive)
              (dired-omit-mode 1)
              (hl-line-mode 1)
              (diredfl-mode 1)
              (diff-hl-dired-mode 1)))

  (use-package dired-single
    :vc (:url "https://codeberg.org/amano.kenji/dired-single")
    :defer t)

  (use-package dired-ranger
    :defer t)

  (use-package dired-collapse
    :defer t)

  (use-package diredfl
    :defer t)
  )

(define-key dired-mode-map "?" dired-mode-map)

Development

Git Gutter

Highlight addition, changes or deletion of lines on the left margin of each file that’s inside a git repository. This helps in quickly identifying the changes in a file. Package: diff-hl

(use-package diff-hl)
(global-diff-hl-mode)
(diff-hl-flydiff-mode 1)
(diff-hl-dired-mode 1)
(diff-hl-margin-mode 1)

Git Link

(use-package git-link
  :defer t
  :custom
  (git-link-default-branch "master"))

Magit

The best git client ever! Package: magit

(use-package magit
  :commands magit-status
  :custom
  (magit-display-buffer-function #'magit-display-buffer-same-window-except-diff-v1))

Terminal

Eat

(use-package eat
  :defer t)

Colorize output in compile buffer

(setq inhibit-read-only t)
(add-hook 'compilation-filter-hook #'ansi-color-compilation-filter)

(setq scroll-conservatively 1000)

Increase function name font size for better readability

Found this in a reddit comment. This helps make the function names stand out a tiny bit and make them more readable/parsable.

(set-face-attribute 'font-lock-function-name-face nil
                    :height 1.1)

Languages

Treesit-auto

Package: treesit-auto This package worked best for setting all the treesitter stuff.

(use-package treesit-auto
  :defer t
  :custom
  (treesit-auto-install 'prompt)
  :config
  (treesit-auto-add-to-auto-mode-alist 'all)
  (global-treesit-auto-mode))

Flymake diagnostics as popups

This is to display any errors or warnings as popups instead of the echo area. The popups are displayed when the point is on a variable that has an error/warning. This is better than what is usually displayed in the echo area (by default) because the text in the echo area gets cut off at the end. Package: flymake-popon

(use-package flymake-popon
  :vc (:url "https://codeberg.org/akib/emacs-flymake-popon.git")
  :defer t)

Eglot

Using the built-in eglot instead of LSP. I previously used LSP and found it to be pretty heavy. In my experience eglot is lighter and gives me pretty much all the functionality that I need.

(use-package jsonrpc
  :defer t)

(use-package typescript-ts-mode
  :defer t
  :mode "\\.ts\\'"
  :hook (typescript-ts-mode . eglot-ensure))

(use-package eglot
  :defer t
  :hook (
         ((typescriptreact-mode typescript-ts-mode) . eglot-ensure)
		 (go-ts-mode . eglot-ensure)
         (python-ts-mode . eglot-ensure)
         (typescriptreact-mode . flymake-popon-mode)
         )
  :config
  (setq eglot-confirm-server-initiated-edits nil)
  (setq eglot-ignored-server-capabilities nil)
  (add-to-list 'eglot-server-programs
			   '((typescript-ts-mode typescript-mode) . ("typescript-language-server" "--stdio"))))

Eglot Booster

Package: eglot-booster

Prerequisites:

(use-package eglot-booster
  :vc (:url "https://github.com/jdtsmith/eglot-booster")
  :after eglot
  :custom
  (eglot-booster-no-remote-boost t)
  :config
  (eglot-booster-mode))

JS Package Mode

(use-package js-pkg-mode
  :vc (:url "https://github.com/ovistoica/js-pkg-mode")
  :hook
  (typescript-ts-mode . js-pkg-mode))

Python

(use-package python
  :ensure t
  :hook ((python-ts-mode . eglot-ensure))
  :mode (("\\.py\\'" . python-ts-mode)))
(use-package python-mode
  :defer t
  :mode "\\.py\\'")
;;    (setq major-mode-remap-alist
;;        '((python-mode . python-ts-mode)))

;; (with-eval-after-load 'eglot
;;   (add-to-list 'eglot-server-programs
;;                '(python-mode . ("pyright-langserver" "--stdio"))
;;                '(python-mode . ("ruff" "server")))
;;   (add-hook 'after-save-hook 'eglot-format))

Typescript

Prettier

Package: prettier

(use-package prettier
  :defer t
  :hook
  (typescript-ts-mode . prettier-mode)
  :custom
  (prettier-mode-sync-config-flag nil))

Jest

(use-package jest-test-mode 
  :ensure t 
  :commands jest-test-mode
  :hook (typescript-ts-mode))

Markdown

Support markdown mode to make README files and other markdown files easily readable.

(use-package markdown-mode
  :ensure t
  :mode ("README\\.md\\'" . gfm-mode)
  :init
  (setq markdown-command "multimarkdown"))

YAML

(use-package yaml-ts-mode
  :defer t
  :mode "\\.yaml\\'")

Golang

(use-package go-ts-mode
  :defer t
  :mode "\\.go\\'")

Go test

Package: gotest-ts This does not correctly work right now. But I’ll keep it and tinker with it.

(use-package gotest-ts
  :hook
  (go-ts-mode . gotest-ts)
  :bind
  ("<f2>" . gotest-ts-run-dwim))

NuShell

(use-package nushell-mode
  :defer t
  :mode "\\.nu\\'")

Aphelia

Package: aphelia

(use-package apheleia
  :hook (
         (go-ts-mode . apheleia-mode)
         (python-mode . apheleia-mode)))

Rest Client

Package: verb

(use-package verb
  :defer t
  :custom
  (verb-auto-kill-response-buffers t))

LLM

gpt.el

Package: gpt.el

Make sure to define the API key from .envrc

(use-package gptel
  :defer t)

;; Perplexity offers an OpenAI compatible API
(gptel-make-openai "Perplexity"         ;Any name you want
  :host "api.perplexity.ai"
  :key pplx-api-key
  :endpoint "/chat/completions"
  :stream t
  :models '(;; has many more, check perplexity.ai
            llama-3.1-sonar-small-128k-chat))

Consult Xref

(use-package consult-xref-stack
  :defer t
  :vc (:url "https://github.com/brett-lempereur/consult-xref-stack" :branch "main")
  :bind
  (("M-," . consult-xref-stack-backward)))

Consult Project Extra

Package: consult-project-extra

(use-package consult-project-extra
  :defer t)

Buffers

Perspectives

Basic Setup

This provides multiple “workspaces” for better management of buffers. Package: perspective.el

(use-package perspective
  :defer t
  :bind (("C-x k" . persp-kill-buffer*))
  :custom
  (persp-mode-prefix-key (kbd "C-c M-p"))
  (persp-initial-frame-name "main")
  (persp-sort 'created)
  :init
  (persp-mode))

IBuffer hook

This is to display buffers under their respective perspectives

(add-hook 'ibuffer-hook
          (lambda ()
            (persp-ibuffer-set-filter-groups)
            (unless (eq ibuffer-sorting-mode 'alphabetic)
              (ibuffer-do-sort-by-alphabetic))))

Saving Sessions

Set the directory for auto saving persp sessions

(setq persp-state-default-file (concat user-emacs-directory "var/persp-auto-save"))
(add-hook 'kill-emacs-hook #'persp-state-save)

Activities

Package: activities.el

(use-package activities
  :init
  (activities-mode)
  (activities-tabs-mode)
  ;; Prevent `edebug' default bindings from interfering.
  (setq edebug-inhibit-emacs-lisp-mode-bindings t)

  :bind
  (("C-x C-a C-n" . activities-new)
   ("C-x C-a C-d" . activities-define)
   ("C-x C-a C-a" . activities-resume)
   ("C-x C-a C-s" . activities-suspend)
   ("C-x C-a C-k" . activities-kill)
   ("C-x C-a RET" . activities-switch)
   ("C-x C-a b" . activities-switch-buffer)
   ("C-x C-a g" . activities-revert)
   ("C-x C-a l" . activities-list)))

Tab Bar Config

(with-eval-after-load 'tab-bar
  (setq tab-bar-new-tab-to 'rightmost)
  (setq tab-bar-new-tab-choice "*scratch*")
  ;; Appearance
  (setq tab-bar-separator 'nil)
  (setq tab-bar-format '(tab-bar-format-tabs tab-bar-separator tab-bar-format-align-right))
  (setq tab-bar-close-button-show t)
  (set-face-attribute 'tab-bar nil
                      :height 1.0) ; background behind all tabs on the tab bar
  (set-face-attribute 'tab-bar-tab nil
                      :overline t) ; the selected tab
  (set-face-attribute 'tab-bar-tab-inactive nil 
                      :box nil) ; unselected tabs
  (setq tab-bar-history-limit 100) ; the default is ten. Why not 1,000? LOL
  )
(custom-set-variables '(tab-bar-select-tab-modifiers '(super)))

OrgMode

Capture Templates

(defun rr/set-org-capture-templates ()
  `(("o" "Organize")
    ("ot" "Task" entry (file+olp, (rr/org-path "organize.org") "Tasks")
     "* TODO %?\n%U\n %i" :kill-buffer t)
    ("oe" "Event" entry (file+olp, (rr/org-path "organize.org") "Events")
     "* TODO %?\n%U\n %i")
    ("og" "Guitar" entry (file+olp, (rr/org-path "organize.org") "Goals" "Guitar" "Practice Log")
     "* %u\n%?")
	
    ("w" "Work")
    ("wt" "Work Task" entry (file+olp, (rr/org-path "work-tasks.org") "Tasks")
     "* TODO %?\n%U\n %i" :kill-buffer t)
    ("wd" "Deep Task" entry (file+olp, (rr/org-path "work-tasks.org") "All Tasks" "Deep")
     "* TODO %?\n%U\n %i" :kill-buffer t)
    ("ws" "Shallow Task" entry (file+olp, (rr/org-path "work-tasks.org") "All Tasks" "Shallow")
     "* TODO %?\n%U\n %i" :kill-buffer t)
    ("wi" "Work Inbox" entry (file+olp, (rr/org-path "work-tasks.org") "Inbox")
     "* %?\n%U\n %i")
    ("wm" "Work Meeting" entry (file+headline, (rr/org-path "work-tasks.org") "Meeting Notes")
     "* %?\n%U\n %i")
    ("wa" "Activity Log" entry (file+olp+datetree, (rr/org-path "work-tasks.org") "Activity Log")
     "* %?\n%U\n %i")

	("m" "Meeting")
    ("mm" "1:1 with Max" entry (file+datetree, "~/Documents/roam-notes/meetings/1on1/max.org")
     "* %U\n- %?\n %i" :kill-buffer t)
    ("mr" "1:1 with Rob" entry (file+datetree, "~/Documents/roam-notes/meetings/1on1/rob.org")
     "* %U\n- %?\n %i" :kill-buffer t)
    ("mj" "1:1 with Joseph" entry (file+datetree, "~/Documents/roam-notes/meetings/1on1/joseph.org")
     "* %U\n- %?\n %i" :kill-buffer t)
	
    ("j" "Journal" entry (file+datetree, (rr/org-path "journal.org"))
     "* %?\n")
	
    ("n" "Notes")
    ("nr" "Resource" entry (file+olp, (rr/org-path "refile.org") "Resources")
     "* %?\n%U\n %i")
    ("nc" "Curiosity" entry (file+olp, (rr/org-path "refile.org") "Curiosities")
     "* %?\n%U\n %i")
    ("no" "Other" entry (file+olp, (rr/org-path "refile.org") "Notes")
     "* %?\n%U\n %i")
	
    ("l" "Life")
    ("lj" "Journal" entry (file+olp+datetree, (rr/org-path "life.org") "Journal") "* %?\n%U\n %i")
    )
  )

Basic setup

(defun rr/org-path (path)
  (expand-file-name path org-directory))

(defun rr/org-mode-setup ()
  (org-indent-mode)
  (variable-pitch-mode 1)
  (auto-fill-mode 0)
  (visual-line-mode)
  (setq org-directory rr-org-mode-dir)
  (setq org-agenda-files (append (directory-files org-directory t "\\.org$") (rr/org-roam-list-notes-by-tag "project")))
  (setq org-capture-templates (rr/set-org-capture-templates))
  (setq org-todo-keywords
        '((sequence "TODO(t)" "STRT(s)" "WAIT(w)" "HOLD(h)" "IDEA(i)" "CODE(c)" "FDBK(f)" "|" "DONE(d!)" "KILL(k!)")
          ))
  (setq org-id-link-to-org-use-id 'use-existing))

(use-package org
  :demand t
  :hook (org-mode . rr/org-mode-setup)
  :config
  ;;    (rr/org-mode-setup)
  (define-key org-mode-map (kbd "C-c C-r") verb-command-map)
  (setq org-ellipsis ""
        org-hide-emphasis-markers t
        org-log-done 'time
        org-log-into-drawer t
        ;; org-adapt-indentation t
        ;; org-element-use-cache nil
        org-special-ctrl-a/e t
        org-insert-heading-respect-content t
        org-tags-column -70
        org-agenda-start-with-log-mode t
        org-agenda-skip-scheduled-if-done t
        org-agenda-skip-deadline-if-done t
        org-agenda-include-deadlines t
        org-agenda-tags-column 100
        org-agenda-include-diary t
        org-catch-invisible-edits 'smart
        org-fontify-whole-heading-line t
        org-fontify-quote-and-verse-blocks t
        org-ctrl-k-protect-subtree t
        org-cycle-separator-lines 0
        org-refile-use-outline-path 'file
        org-outline-path-complete-in-steps nil
		org-tag-alist '(;; Places
						("@home" . ?H)
						("@work" . ?W)
						;; Devices
						("@phone" . ?P)
						("@computer" . ?C)
						;; Activities
						("@writing" . ?w)
						("@errands" . ?r)
						("@email" . ?e)
						("@call" . ?c)
						)
        org-refile-allow-creating-parent-nodes 'confirm
        org-refile-targets
        '((nil :maxlevel . 6)
          (org-agenda-files :maxlevel . 6)))

  (advice-add 'org-refile :after 'org-save-all-org-buffers))

(require 'org-indent)

Org Export Git Flavored Markdown

Export buffers/subtrees to git flavored markdown Package: ox-gfm

(use-package ox-gfm
  :after org)

Org Appear

This is to make emphasis markers like bold or italics show up when cursor is on the words that contain said markers. Package: org-appear

(use-package org-appear
  :after org)
(add-hook 'org-mode-hook 'org-appear-mode)

Prettier bullets

Package: org-bullets

(use-package org-bullets
  :after org
  :hook (org-mode . org-bullets-mode)
  :custom
  (org-bullets-bullet-list '("" "" "" "" "" "" "")))

Echo area tooltips

Shows tooltips in echo area. For example, if the point is on a hyperlink, the echo area shows what that link is. Found it in a reddit thread.

(defun echo-area-tooltips ()
  "Show tooltips in the echo area automatically for current buffer."
  (setq-local help-at-pt-display-when-idle t
              help-at-pt-timer-delay 0)
  (help-at-pt-cancel-timer)
  (help-at-pt-set-timer))

(add-hook 'org-mode-hook #'echo-area-tooltips)

Visual Fill Column

Make the fill column 100 characters long and enable visual-line-mode in it. Package: visual-fill-column

(defun rr/org-mode-visual-fill ()
  (setq visual-fill-column-width 120
        visual-fill-column-center-text t)
  (visual-fill-column-mode 1))

(use-package visual-fill-column
  :after org
  :hook (org-mode . rr/org-mode-visual-fill))

Agenda Configs

This needs a lot more work, but this is a good start

Adding org-super-agenda to pimp up my agenda config:

(use-package org-super-agenda
  :after org
  :defer t
  :init
  (org-super-agenda-mode))

The following are some custom agenda commands

(setq org-agenda-span 'day)

(setq org-agenda-custom-commands
      `(("d" "Dashboard"
         ((agenda "" ((org-deadline-warning-days 7)))
          (tags-todo "+PRIORITY=\"A\""
                     ((org-agenda-overriding-header "High Priority")))
          (todo "STRT"
                ((org-agenda-overriding-header "In Progress")
                 (org-agenda-max-todos nil)))
          (todo "TODO"
                ((org-agenda-overriding-header "Unprocessed Inbox Tasks")))))
        ("w" "Work Tasks"
         ((agenda "" ((org-deadline-warning-days 7))
				  (tags-todo "+work-meeting"
							 ((org-agenda-overriding-header "Work Tasks")))
				  )))
        ("%" "Appointments" agenda* "Today's appointments"
         ((org-agenda-span 1)
          (org-agenda-max-entries 3)))
		("f" "Follow up"
		 ((tags-todo "+followup"
					 ((org-agenda-overriding-header "Follow-up Tasks")))
		  (tags-todo "-{.*}"
					 ((org-agenda-overriding-header "Untagged Tasks")))))
		("r" "Weekly Review"
		 ((agenda ""
				  ((org-agenda-overriding-header "Completed Tasks")
				   (org-agenda-skip-function '(org-agenda-skip-entry-if 'nottodo 'done))
				   (org-agenda-span 'week)))
		  (agenda ""
				  ((org-agenda-overriding-header "Unfinished Scheduled Tasks")
				   (org-agenda-skip-function '(org-agenda-skip-entry-if 'todo 'done))
				   (org-agenda-span 'week)))))
		("u" "Super View"
		 ((agenda "" ((org-agenda-span 1)
					  (org-super-agenda-groups
					   '(
						 (:name "Today"
								:time-grid t
								:date today
								:scheduled today
								:order 1
								:face 'warning
								)
						 (:name "Overdue"
								:deadline past
								:face 'error
								)
						 (:name "Reschedule"
								:scheduled past
								:face 'error
								)
						 (:name "Projects"
								:tag ("project" "@proj")
								)
						 (:name "Due soon"
								:deadline future
								:scheduled future)
						 ))))))
		))

Babel Configuration

Configure Babel Languages

(with-eval-after-load 'org
  (org-babel-do-load-languages
   'org-babel-load-languages
   '((emacs-lisp . t)
     (python . t)
     (shell . t))))

(setq org-confirm-babel-evaluate nil)

(with-eval-after-load 'org
  (require 'org-tempo)
  (add-to-list 'org-structure-template-alist '("el" . "src emacs-lisp")))

Source Language Modes

This is for emacs to recognize and provide syntax highlighting for config files that have a similar format in unix based systems (key-value pairs)

;; This may not be needed
(push '("conf-unix" . conf-unix) org-src-lang-modes)

Auto-tangle Configuration Files

;; Automatically tangle PrivateConfig.org config file when we save it
(defun rr/org-babel-tangle-config ()
  (when (string-match "dotfiles\/" (buffer-file-name))
    ;; Dynamic scoping to the rescue
    (let ((org-confirm-babel-evaluate nil))
      (org-babel-tangle))))

(add-hook 'org-mode-hook (lambda () (add-hook 'after-save-hook #'rr/org-babel-tangle-config)))

Generate Table of Contents

It’s nice to generate table of contents at the top of the org file for easy navigation. Package: org-make-toc

(use-package org-make-toc
  :after org)

(defun rr/enable-org-make-toc-mode ()
  (if (equal (buffer-name) "PostInitConfig.org")
      (org-make-toc-mode)))

(add-hook 'find-file-hook 'rr/enable-org-make-toc-mode)

Org todo keyword faces

(setq org-todo-keyword-faces
      '(("WAIT" . (:foreground "#e6bf85" :weight bold))
        ("TODO" . (:foreground "#a0bc70" :weight bold))
        ("STRT" . (:foreground "#a7a2dc" :weight bold))
        ("HOLD" . (:foreground "#e6bf85" :weight bold))
        ("CODE" . (:foreground "#e6bf85" :weight bold))
        ("FDBK" . (:foreground "#e6bf85" :weight bold))
        ("IDEA" . (:foreground "#fdac37" :weight bold))
        ("DONE" . (:foreground "#5c6267" :weight bold))
        ("KILL" . (:foreground "#ee7570" :weight bold))))

Org faces

Currently trying out this setting with fixed width and variable width fonts. May change soon.

(set-face-attribute 'org-document-title nil :font my-variable-pitch-font :weight 'regular :height 1.5)

(dolist (face '((org-level-1 . 1.3)
                (org-level-2 . 1.2)
                (org-level-3 . 1.15)
                (org-level-4 . 1.0)
                (org-level-5 . 1.1)
                (org-level-6 . 1.1)
                (org-level-7 . 1.1)
                (org-level-8 . 1.1)))
  (set-face-attribute (car face) nil :font my-variable-pitch-font :weight 'regular :height (cdr face))

  ;; Original background color of org-block: #3B3D4A
  (set-face-attribute 'org-block nil :foreground "unspecified" :background "#2D313B" :inherit 'fixed-pitch)
  (set-face-attribute 'org-table nil  :inherit 'fixed-pitch)
  (set-face-attribute 'org-todo nil  :inherit 'fixed-pitch)
  (set-face-attribute 'org-formula nil  :inherit 'fixed-pitch)
  (set-face-attribute 'org-list-dt nil  :inherit 'fixed-pitch)
  (set-face-attribute 'org-code nil   :inherit '(shadow fixed-pitch))
  (set-face-attribute 'org-indent nil :inherit '(org-hide fixed-pitch))
  (set-face-attribute 'org-verbatim nil :inherit '(shadow fixed-pitch))
  (set-face-attribute 'org-special-keyword nil :inherit '(font-lock-comment-face fixed-pitch))
  (set-face-attribute 'org-meta-line nil :inherit '(font-lock-comment-face fixed-pitch))
  (set-face-attribute 'org-checkbox nil :inherit 'fixed-pitch)
  (set-face-attribute 'org-tag nil :foreground "#5A5D67")
  ;;(set-face-attribute 'hl-line nil :background "#0d3b66")
  (set-face-attribute 'org-column nil :background "unspecified")
  (set-face-attribute 'org-column-title nil :background "unspecified"))

Org Behaviors

Org RET key behavior

RET can be used in variety of places - toggling TODO items, toggling checkboxes, opening links, etc. The following fuctions are copied over from Doom and help make RET more intuitive in org-mode.

Org get todo keywords for

This function is called by +org/dwim-at-point

(defun +org-get-todo-keywords-for (&optional keyword)
  "Returns the list of todo keywords that KEYWORD belongs to."
  (when keyword
    (cl-loop for (type . keyword-spec)
             in (cl-remove-if-not #'listp org-todo-keywords)
             for keywords =
             (mapcar (lambda (x) (if (string-match "^\\([^(]+\\)(" x)
                                     (match-string 1 x)
                                   x))
                     keyword-spec)
             if (eq type 'sequence)
             if (member keyword keywords)
             return keywords)))

Org dwim-at-point

This is copied over from Doom Emacs. This function basically interprets RET as one of several things based on the context. On a checkbox, it toggles the checkbox, on a TODO heading it toggles that, on a link it opens the link in a browser, etc. Makes everything very intuitive.

(defun +org/dwim-at-point (&optional arg)
  "Do-what-I-mean at point.

If on a:
- checkbox list item or todo heading: toggle it.
- clock: update its time.
- headline: cycle ARCHIVE subtrees, toggle latex fragments and inline images in
  subtree; update statistics cookies/checkboxes and ToCs.
- footnote reference: jump to the footnote's definition
- footnote definition: jump to the first reference of this footnote
- table-row or a TBLFM: recalculate the table's formulas
- table-cell: clear it and go into insert mode. If this is a formula cell,
  recaluclate it instead.
- babel-call: execute the source block
- statistics-cookie: update it.
- latex fragment: toggle it.
- link: follow it
- otherwise, refresh all inline images in current tree."
  (interactive "P")
  (if (button-at (point))
      (call-interactively #'push-button)
    (let* ((context (org-element-context))
           (type (org-element-type context)))
      ;; skip over unimportant contexts
      (while (and context (memq type '(verbatim code bold italic underline strike-through subscript superscript)))
        (setq context (org-element-property :parent context)
              type (org-element-type context)))
      (pcase type
        (`headline
         (cond ((memq (bound-and-true-p org-goto-map)
                      (current-active-maps))
                (org-goto-ret))
               ((and (fboundp 'toc-org-insert-toc)
                     (member "TOC" (org-get-tags)))
                (toc-org-insert-toc)
                (message "Updating table of contents"))
               ((string= "ARCHIVE" (car-safe (org-get-tags)))
                (org-force-cycle-archived))
               ((or (org-element-property :todo-type context)
                    (org-element-property :scheduled context))
                (org-todo
                 (if (eq (org-element-property :todo-type context) 'done)
                     (or (car (+org-get-todo-keywords-for (org-element-property :todo-keyword context)))
                         'todo)
                   'done))))
         ;; Update any metadata or inline previews in this subtree
         (org-update-checkbox-count)
         (org-update-parent-todo-statistics)
         (when (and (fboundp 'toc-org-insert-toc)
                    (member "TOC" (org-get-tags)))
           (toc-org-insert-toc)
           (message "Updating table of contents"))
         (let* ((beg (if (org-before-first-heading-p)
                         (line-beginning-position)
                       (save-excursion (org-back-to-heading) (point))))
                (end (if (org-before-first-heading-p)
                         (line-end-position)
                       (save-excursion (org-end-of-subtree) (point))))
                (overlays (ignore-errors (overlays-in beg end)))
                (latex-overlays
                 (cl-find-if (lambda (o) (eq (overlay-get o 'org-overlay-type) 'org-latex-overlay))
                             overlays))
                (image-overlays
                 (cl-find-if (lambda (o) (overlay-get o 'org-image-overlay))
                             overlays)))
           (+org--toggle-inline-images-in-subtree beg end)
           (if (or image-overlays latex-overlays)
               (org-clear-latex-preview beg end)
             (org--latex-preview-region beg end))
           ))

        (`clock (org-clock-update-time-maybe))

        (`footnote-reference
         (org-footnote-goto-definition (org-element-property :label context)))

        (`footnote-definition
         (org-footnote-goto-previous-reference (org-element-property :label context)))

        ((or `planning `timestamp)
         (org-follow-timestamp-link))

        ((or `table `table-row)
         (if (org-at-TBLFM-p)
             (org-table-calc-current-TBLFM)
           (ignore-errors
             (save-excursion
               (goto-char (org-element-property :contents-begin context))
               (org-call-with-arg 'org-table-recalculate (or arg t))))))

        (`table-cell
         (org-table-blank-field)
         (org-table-recalculate arg)
         (when (and (string-empty-p (string-trim (org-table-get-field)))
                    (bound-and-true-p evil-local-mode))
           (evil-change-state 'insert)))

        (`babel-call
         (org-babel-lob-execute-maybe))

        (`statistics-cookie
         (save-excursion (org-update-statistics-cookies arg)))

        ((or `src-block `inline-src-block)
         (org-babel-execute-src-block arg))

        ((or `latex-fragment `latex-environment)
         (org-latex-preview arg))

        (`link
         (let* ((lineage (org-element-lineage context '(link) t))
                (path (org-element-property :path lineage)))
           (if (or (equal (org-element-property :type lineage) "img")
                   (and path (image-type-from-file-name path)))
               (+org--toggle-inline-images-in-subtree
                (org-element-property :begin lineage)
                (org-element-property :end lineage))
             (org-open-at-point arg))))

        ((guard (org-element-property :checkbox (org-element-lineage context '(item) t)))
         (let ((match (and (org-at-item-checkbox-p) (match-string 1))))
           (org-toggle-checkbox (if (equal match "[ ]") '(16)))))

        (_
         (if (or (org-in-regexp org-ts-regexp-both nil t)
                 (org-in-regexp org-tsr-regexp-both nil  t)
                 (org-in-regexp org-link-any-re nil t))
             (call-interactively #'org-open-at-point)
           (+org--toggle-inline-images-in-subtree
            (org-element-property :begin context)
            (org-element-property :end context))))))))

Org links behavior

Got it from: Emacs DWIM: do what ✨I✨ mean

(defun rr/org-insert-link-dwim ()
  "Like `org-insert-link' but with personal dwim preferences."
  (interactive)
  (let* ((point-in-link (org-in-regexp org-link-any-re 1))
         (clipboard-url (when (string-match-p "^http" (current-kill 0))
                          (current-kill 0)))
         (region-content (when (region-active-p)
                           (buffer-substring-no-properties (region-beginning)
                                                           (region-end)))))
    (cond ((and region-content clipboard-url (not point-in-link))
           (delete-region (region-beginning) (region-end))
           (insert (org-make-link-string clipboard-url region-content)))
          ((and clipboard-url (not point-in-link))
           (insert (org-make-link-string
                    clipboard-url
                    (read-string "title: "
                                 (with-current-buffer (url-retrieve-synchronously clipboard-url)
                                   (dom-text (car
                                              (dom-by-tag (libxml-parse-html-region
                                                           (point-min)
                                                           (point-max))
                                                          'title))))))))
          (t
           (call-interactively 'org-insert-link)))))

Org cycle behavior

I really liked Doom style org cycling. It just goes through folded and children modes and doesn’t enter subtree. As my note structure grows, there will invariably be lot of nested headings and looking at all the notes at once adds no value. So, just cycling between FOLDED and CHILDREN works perfectly for me. The below code is copied over from Doom’s config.

Set up function for custom cycling

I want TAB to just open or fold the current heading. I can use Shift+TAB if I want to open everything. This function handles it. Stole it from doom-emacs.

(defun +org-cycle-only-current-subtree-h (&optional arg)
  "Toggle the local fold at the point, and no deeper.
       `org-cycle's standard behavior is to cycle between three levels: collapsed,
       subtree and whole document. This is slow, especially in larger org buffer. Most
       of the time I just want to peek into the current subtree -- at most, expand
       *only* the current subtree.

       All my (performant) foldings needs are met between this and `org-show-subtree'
       (on zO for evil users), and `org-cycle' on shift-TAB if I need it."
  (interactive "P")
  (unless (eq this-command 'org-shifttab)
    (save-excursion
      (org-beginning-of-line)
      (let (invisible-p)
        (when (and (org-at-heading-p)
                   (or org-cycle-open-archived-trees
                       (not (member org-archive-tag (org-get-tags))))
                   (or (not arg)
                       (setq invisible-p (outline-invisible-p (line-end-position)))))
          (unless invisible-p
            (setq org-cycle-subtree-status 'subtree))
          (org-cycle-internal-local)
          t)))))

Org insert behavior

Insert item

(defun +org--insert-item (direction)
  (let ((context (org-element-lineage
                  (org-element-context)
                  '(table table-row headline inlinetask item plain-list)
                  t)))
    (pcase (org-element-type context)
      ;; Add a new list item (carrying over checkboxes if necessary)
      ((or `item `plain-list)
       ;; Position determines where org-insert-todo-heading and org-insert-item
       ;; insert the new list item.
       (if (eq direction 'above)
           (org-beginning-of-item)
         (org-end-of-item)
         (backward-char))
       (org-insert-item (org-element-property :checkbox context))
       ;; Handle edge case where current item is empty and bottom of list is
       ;; flush against a new heading.
       (when (and (eq direction 'below)
                  (eq (org-element-property :contents-begin context)
                      (org-element-property :contents-end context)))
         (org-end-of-item)
         (org-end-of-line)))

      ;; Add a new table row
      ((or `table `table-row)
       (pcase direction
         ('below (save-excursion (org-table-insert-row t))
                 (org-table-next-row))
         ('above (save-excursion (org-shiftmetadown))
                 (+org/table-previous-row))))

      ;; Otherwise, add a new heading, carrying over any todo state, if
      ;; necessary.
      (_
       (let ((level (or (org-current-level) 1)))
         ;; I intentionally avoid `org-insert-heading' and the like because they
         ;; impose unpredictable whitespace rules depending on the cursor
         ;; position. It's simpler to express this command's responsibility at a
         ;; lower level than work around all the quirks in org's API.
         (pcase direction
           (`below
            (let (org-insert-heading-respect-content)
              (goto-char (line-end-position))
              (org-end-of-subtree)
              (insert "\n" (make-string level ?*) " ")))
           (`above
            (org-back-to-heading)
            (insert (make-string level ?*) " ")
            (save-excursion (insert "\n"))))
         (when-let* ((todo-keyword (org-element-property :todo-keyword context))
                     (todo-type    (org-element-property :todo-type context)))
           (org-todo
            (cond ((eq todo-type 'done)
                   ;; Doesn't make sense to create more "DONE" headings
                   (car (+org-get-todo-keywords-for todo-keyword)))
                  (todo-keyword)
                  ('todo)))))))

    (when (org-invisible-p)
      (org-show-hidden-entry))
    (when (and (bound-and-true-p evil-local-mode)
               (not (evil-emacs-state-p)))
      (evil-insert 1))))

Insert item below

Note: Yet to add keybinding to this function

(defun +org/insert-item-below (count)
  "Inserts a new heading, table cell or item below the current one."
  (interactive "p")
  (dotimes (_ count) (+org--insert-item 'below)))

(with-eval-after-load 'org
  (define-key org-mode-map (kbd "M-RET") '+org/insert-item-below))

Insert item above

Note: Yet to add keybinding to this function

(defun +org/insert-item-above (count)
  "Inserts a new heading, table cell or item above the current one."
  (interactive "p")
  (dotimes (_ count) (+org--insert-item 'above)))

Org refile to current file

Copied over from doom emacs. Helps make refiling easier when it must be done within the current file.

(defun +org/refile-to-current-file (arg &optional file)
  "Refile current heading to elsewhere in the current buffer.
If prefix ARG, copy instead of move."
  (interactive "P")
  (let ((org-refile-targets `((,file :maxlevel . 10)))
        (org-refile-use-outline-path nil)
        (org-refile-keep arg)
        current-prefix-arg)
    (call-interactively #'org-refile)))

Org show next/prev headings tidily

Taken from: https://orgmode.org/worg/org-hacks.html#orge99b7a9

(defun rr/org-show-next-heading-tidily ()
  "Show next entry, keeping other entries closed."
  (interactive)
  (if (save-excursion (end-of-line) (outline-invisible-p))
      (progn (org-show-entry) (show-children))
    (outline-next-heading)
    (unless (and (bolp) (org-on-heading-p))
      (org-up-heading-safe)
      (hide-subtree)
      (error "Boundary reached"))
    (org-overview)
    (org-reveal t)
    (org-show-entry)
    (show-children)))

(global-set-key (kbd "M-n") 'rr/org-show-next-heading-tidily)

(defun rr/org-show-previous-heading-tidily ()
  "Show previous entry, keeping other entries closed."
  (interactive)
  (let ((pos (point)))
    (outline-previous-heading)
    (unless (and (< (point) pos) (bolp) (org-on-heading-p))
      (goto-char pos)
      (hide-subtree)
      (error "Boundary reached"))
    (org-overview)
    (org-reveal t)
    (org-show-entry)
    (show-children)))

(global-set-key (kbd "M-p") 'rr/org-show-previous-heading-tidily)

Org sort list by checkbox type

Taken from: https://orgmode.org/worg/org-hacks.html#org5a09194

(defun rr/org-sort-list-by-checkbox-type ()
  "Sort list items according to Checkbox state."
  (interactive)
  (org-sort-list
   nil ?f
   (lambda ()
     (if (looking-at org-list-full-item-re)
         (cdr (assoc (match-string 3)
                     '(("[X]" . 4) ("[-]" . 3) ("[ ]" . 2) (nil . 1))))
       4))))

Mark heading DONE when all checkboxes are checked

Taken from: https://orgmode.org/worg/org-hacks.html#mark-done-when-all-checkboxes-checked

(eval-after-load 'org-list
  '(add-hook 'org-checkbox-statistics-hook (function rr/checkbox-list-complete)))

(defun rr/checkbox-list-complete ()
  (save-excursion
    (org-back-to-heading t)
    (let ((beg (point)) end)
      (end-of-line)
      (setq end (point))
      (goto-char beg)
      (if (re-search-forward "\\[\\([0-9]*%\\)\\]\\|\\[\\([0-9]*\\)/\\([0-9]*\\)\\]" end t)
          (if (match-end 1)
              (if (equal (match-string 1) "100%")
                  ;; all done - do the state change
                  (org-todo 'done)
                (org-todo 'todo))
            (if (and (> (match-end 2) (match-beginning 2))
                     (equal (match-string 2) (match-string 3)))
                (org-todo 'done)
              (org-todo 'todo)))))))

Org Roam

Zettelkasten-style note taking

Basic Setup

Sets up org-roam, roam directory, few useful keybindings.

(use-package org-roam
  :defer 2
  :custom
  (org-roam-directory rr-org-roam-dir)
  (org-roam-dailies-directory "journals/")
  (org-roam-completion-everywhere t)
  (org-roam-capture-templates
   '(("d" "Default" plain
      "%?"
      :if-new (file+head "%<%Y%m%d%H%M%S>-${slug}.org" "#+title: ${title}\n")
      :unnarrowed t)
     ("p" "Project" plain
      (file "~/org-mode/roam/work/templates/projectNoteTemplate.org")
      :if-new (file+head "%<%Y%m%d%H%M%S>-${slug}.org" "#+title: ${title}\n#+category: ${title}\n#+filetags:project")
      :unnarrowed t)
     
     ("m" "Meeting" plain
      (file "~/org-mode/roam/work/templates/meetingTemplate.org")
      :if-new (file+head "%<%Y%m%d%H%M%S>-${slug}.org" "#+title: ${title}\n#+filetags:meeting")
      :unnarrowed t)
     )
   )
  (org-roam-dailies-capture-templates
   '(("d" "default" entry "* %?\n[%<%I:%M %p>]\n" :target
      (file+head "%<%Y-%m-%d>.org" "#+title: %<%Y-%m-%d>\n#+filetags:%<%Yw%V>\n")))
   )
  :bind (("C-c n l" . org-roam-buffer-toggle)
         ("C-c n f" . org-roam-node-find)
         ("C-c n i" . org-roam-node-insert)
         ("C-c n I" . org-roam-node-insert-immediate)
         ("C-c n a" . org-roam-tag-add)
         ("C-c n d" . org-roam-dailies-map)
         )
  :config
  (setq org-roam-node-display-template (concat "${title:*} " (propertize "${tags:10}" 'face 'org-tag)))
  (org-roam-setup))

Agenda configs

(defun rr/org-roam-filter-by-tag (tag-name)
  (lambda (node)
  	(member tag-name (org-roam-node-tags node))))

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

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

;;  (rr/org-roam-refresh-agenda-list)

Default Project Template

(defun rr/org-roam-project-finalize-hook ()
  "Adds the captured project file to `org-agenda-files' if the
  capture was not aborted."
  ;; Remove the hook since it was added temporarily
  (remove-hook 'org-capture-after-finalize-hook #'rr/org-roam-project-finalize-hook)

  ;; Add project file to the agenda list if the capture was confirmed
  (unless org-note-abort
    (with-current-buffer (org-capture-get :buffer)
      (add-to-list 'org-agenda-files (buffer-file-name)))))

(defun rr/org-roam-find-project ()
  (interactive)
  ;; Add the project file to the agenda after capture is finished
  (add-hook 'org-capture-after-finalize-hook #'rr/org-roam-project-finalize-hook)

  ;; Select a project file to open, creating it if necessary
  (org-roam-node-find
   nil
   nil
   (rr/org-roam-filter-by-tag "project")
   nil
   :templates
   '(("p" "project" plain
      (file "~/org-mode/roam/work/templates/projectNoteTemplate.org")
  	  :if-new (file+head "%<%Y%m%d%H%M%S>-${slug}.org" "#+title: ${title}\n#+category: ${title}\n#+filetags: project")
  	  :unnarrowed t))))

(global-set-key (kbd "C-c n p") #'rr/org-roam-find-project)

Capture a task directly into a specific project

(defun rr/org-roam-capture-task ()
  (interactive)
  ;; Add the project file to the agenda after capture is finished
  (add-hook 'org-capture-after-finalize-hook #'rr/org-roam-project-finalize-hook)

  ;; Capture the new task, creating the project file if necessary
  (org-roam-capture- :node (org-roam-node-read
                            nil
                            (rr/org-roam-filter-by-tag "project"))
                     :templates '(("p" "project" plain "** TODO %?"
                                   :if-new (file+head+olp "%<%Y%m%d%H%M%S>-${slug}.org"
                                                          "#+title: ${title}\n#+category: ${title}\n#+filetags: project"
                                                          ("Tasks"))))))
(global-set-key (kbd "C-c n t") #'rr/org-roam-capture-task)

Automatically copy (or move) completed tasks to dailies

(defun rr/org-roam-copy-todo-to-today ()
  (interactive)
  (let ((org-refile-keep t) ;; Set this to nil to delete the original!
        (org-roam-dailies-capture-templates
         '(("t" "tasks" entry "%?"
            :if-new (file+head+olp "%<%Y-%m-%d>.org" "#+title: %<%Y-%m-%d>\n" ("Tasks")))))
        (org-after-refile-insert-hook #'save-buffer)
        today-file
        pos)
    (save-window-excursion
      (org-roam-dailies--capture (current-time) t)
      (setq today-file (buffer-file-name))
      (setq pos (point)))

    ;; Only refile if the target file is different than the current file
    (unless (equal (file-truename today-file)
                   (file-truename (buffer-file-name)))
      (org-refile nil nil (list "Tasks" today-file nil pos)))))

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

Insert new note immediately

Without opening a new buffer while writing a note.

(defun org-roam-node-insert-immediate (arg &rest args)
  (interactive "P")
  (let ((args (cons arg args))
        (org-roam-capture-templates (list (append (car org-roam-capture-templates) '(:immediate-finish t)))))
    (apply #'org-roam-node-insert args)))

Org Roam UI

This gives a really nice UI for your org-roam database. The UI not only shows all the nodes in a graph view, but also the contents of all the notes, the backlinks, filtering and several other customizations. It’s great to capture all the notes via org-roam and view them using org-roam-ui. Package: org-roam-ui

(use-package org-roam-ui
  :vc
  (:url "https://github.com/org-roam/org-roam-ui" :branch "main")
  :after org-roam
  ;;         normally we'd recommend hooking orui after org-roam, but since org-roam does not have
  ;;         a hookable mode anymore, you're advised to pick something yourself
  ;;         if you don't care about startup time, use
  ;;  :hook (after-init . org-roam-ui-mode)
  :config
  (setq org-roam-ui-sync-theme t
        org-roam-ui-follow t
        org-roam-ui-update-on-save t
        org-roam-ui-open-on-start t))

Blogging

ox-hugo

This is the emacs package I use to publish to my Hugo website using org files Package: ox-hugo

(use-package ox-hugo
  :after ox)

Turn on org-hugo-auto-export-mode when you visit blog.org

The minor mode org-hugo-auto-export-mode enables auto export hugo posts on saving. However, this minor mode is disabled by default. It doesn’t make sense to have this turned on globally. So, the following piece of code enables the minor mode only when the buffer is blog.org. Found the code in a stack overflow post.

(defun rr/enable-hugo-auto-export-mode ()
  (if (equal (buffer-name) "blog.org")
      (org-hugo-auto-export-mode)))

(add-hook 'find-file-hook 'rr/enable-hugo-auto-export-mode)

Generate a filename given a blog post title

This is a nice little helper function I wrote for myself to generate a filename from a blog post’s title. ox-hugo needs a property called EXPORT_FILE_NAME which must be set under the heading that contains the blog post. This function generates the file name and sets the property based on the org heading the point is on.

(defun rr/extract-hugo-post-file-name ()
  "Create a filename out of blog post's title.

This method is expected to be executed on a TODO heading on a an
org file containing blog posts that would be exported using
ox-hugo. Running this interactive command would set an org
property called EXPORT_FILE_NAME that is required by ox-hugo to
generate a Hugo-friendly markdown file in the location specified
in HUGO_BASE_DIR property."
  (interactive)
  (setq-local blog-post-title (nth 4 (org-heading-components)))
  (let* ((file-name (replace-regexp-in-string "_+" "-" (replace-regexp-in-string "\\W" "_" (string-trim (downcase blog-post-title)))))
         (blog-post-file-name (concat file-name ".md")))
    (org-set-property "EXPORT_FILE_NAME" blog-post-file-name)))

Machine-specific config

This helps keep certain packages separate, like having the copilot package in the additional-config.el will make it load only in the work Emacs instance since I don’t need it on the personal instance.

(if (file-exists-p "~/bin/additional-config.el")
    (progn
      (message "additional config exists")
      (load "~/bin/additional-config.el")))