NixOS/dotfiles/doom/config.org

43 KiB
Executable File
Raw Blame History

JawZ's Doom Emacs config

ABOUT THIS CONFIG

This is my personal Doom Emacs config file, forked from DT's config file on GitLab and modified to fit my personal preferences, plugins, extensions and other customization settings.

The purpose of this file, is to have an easy-to-read documentation which explains why and how each customization works, for future editing and other friends to use.

BIBLE

Allows me to insert bible quotes into my org notes. NOTE I'm not religious just for worldbuilding purposes lol.

(use-package
  insert-esv
  :init
  (setq insert-esv-crossway-api-key "bb1872462ecc59624c7bb8ab36c9701ce2027cd1")
  (setq insert-esv-include-short-copyright 'false)
  (setq insert-esv-include-headings 'true)
  (setq insert-esv-include-passage-horizontal-lines 'false)
  (setq insert-esv-line-length '500)
  :bind ("C-x C-e" . insert-esv-passage))

BOOKMARKS AND BUFFERS

Doom Emacs uses 'SPC b' for keybindings related to bookmarks and buffers.

Bookmarks

Emacs bookmarking works somewhat like registers in that they record positions you can jump to. Unlike registers, they have long names, and they persist automatically from one Emacs session to the next. The prototypical use of bookmarks is to record where you were reading in bookmarked files.

COMMAND DESCRIPTION KEYBINDING
list-bookmarks List bookmarks SPC b L
bookmark-set Set bookmark SPC b m
bookmark-delete Delete bookmark SPC b M
bookmark-save Save current bookmark to bookmark file SPC b w
(setq bookmark-default-file "~/.config/doom/bookmarks")

(map! :leader
      (:prefix ("b". "buffer")
       :desc "List bookmarks"                          "L" #'list-bookmarks
       :desc "Set bookmark"                            "m" #'bookmark-set
       :desc "Delete bookmark"                         "M" #'bookmark-set
       :desc "Save current bookmarks to bookmark file" "w" #'bookmark-save))

Buffers

Regarding buffers, the text you are editing in Emacs resides in an object called a buffer. Each time you visit a file, a buffer holds the files text. Each time you invoke Dired, a buffer holds the directory listing. Ibuffer is a program that lists all of your Emacs buffers, allowing you to navigate between them and filter them.

COMMAND DESCRIPTION KEYBINDING
ibuffer Launch ibuffer SPC b i
kill-buffer Kill current buffer SPC b k
next-buffer Goto next buffer SPC b n
previous-buffer Goto previous buffer SPC b p
save-buffer Save current buffer SPC b s

Global Auto Revert

A buffer can get out of sync with respect to its visited file on disk if that file changes by another program. To keep it up to date, you can enable Auto Revert mode by typing M-x auto-revert-mode, or you can set to turn on globally with global-auto-revert-mode. I have also turned on Global Auto Revert on non-file buffers, which is especially useful for dired buffers.

(global-auto-revert-mode 1)
(setq global-auto-revert-non-file-buffers t)

Keybindings within ibuffer mode

ibuffer mode, it's a more elegant way to display your opened buffers, and plus you can manipulate them using vim keybindings.

COMMAND DESCRIPTION KEYBINDING
ibuffer-mark-forward Mark the buffer m
ibuffer-unmark-forward Unmark the buffer u
ibuffer-do-kill-on-deletion-marks Kill the marked buffers x
ibuffer-filter-by-content ibuffer filter by content f c
ibuffer-filter-by-directory ibuffer filter by directory f d
ibuffer-filter-by-filename ibuffer filter by filename (full path) f f
ibuffer-filter-by-mode ibuffer filter by mode f m
ibuffer-filter-by-name ibuffer filter by name f n
ibuffer-filter-disable Disable ibuffer filter f x
ibuffer-do-kill-lines Hide marked buffers g h
ibuffer-update Restore hidden buffers g H
(evil-define-key 'normal ibuffer-mode-map
  (kbd "f c") 'ibuffer-filter-by-content
  (kbd "f d") 'ibuffer-filter-by-directory
  (kbd "f f") 'ibuffer-filter-by-filename
  (kbd "f m") 'ibuffer-filter-by-mode
  (kbd "f n") 'ibuffer-filter-by-name
  (kbd "f x") 'ibuffer-filter-disable
  (kbd "g h") 'ibuffer-do-kill-lines
  (kbd "g H") 'ibuffer-update)

DASHBOARD

Emacs Dashboard is a startup screen showing you recent files, bookmarks, agenda items and an Emacs banner.

Dashboard in Emacsclient

This setting ensures that emacsclient always opens on dashboard rather than scratch.

(setq doom-fallback-buffer "*dashboard*")

DIRED

The file manager within Emacs. Below, I setup keybindings for image previews (peep-dired). Doom Emacs does not use 'SPC d' for any of its keybindings, so I've chosen the format of 'SPC d' plus 'key'.

Keybindings To Open Dired

COMMAND DESCRIPTION KEYBINDING
dired Open dired file manager SPC d d
dired-jump Jump to current directory in dired SPC d j

Basic dired commands

COMMAND DESCRIPTION KEYBINDING
dired-view-file View file in dired SPC d v
dired-up-directory Go up in directory tree h
dired-find-file Go down in directory tree (or open if file) l
dired-next-line Move down to next line j
dired-previous-line Move up to previous line k
dired-mark Mark file at point m
dired-unmark Unmark file at point u
dired-do-copy Copy current file or marked files C
dired-do-rename Rename current file or marked files R
dired-hide-details Toggle detailed listings on/off (
dired-git-info-mode Toggle git information on/off )
dired-create-directory Create new empty directory +
dired-diff Compare file at point with another =
dired-subtree-toggle Toggle viewing subtree at point TAB

Dired commands using regex

COMMAND DESCRIPTION KEYBINDING
dired-mark-files-regexp Mark files using regex % m
dired-do-copy-regexp Copy files using regex % C
dired-do-rename-regexp Rename files using regex % R
dired-mark-files-regexp Mark all files using regex * %

File permissions and ownership

COMMAND DESCRIPTION KEYBINDING
dired-do-chgrp Change the group of marked files g G
dired-do-chmod Change the mode of marked files M
dired-do-chown Change the owner of marked files O
dired-do-rename Rename file or all marked files R
(map! :leader
      (:prefix ("d" . "dired")
       :desc "Open dired" "d" #'dired
       :desc "Dired jump to current" "j" #'dired-jump)
      (:after dired
       (:map dired-mode-map
        :desc "Peep-dired image previews" "d p" #'peep-dired
        :desc "Dired view file" "d v" #'dired-view-file)))

(evil-define-key 'normal dired-mode-map
  (kbd "M-RET") 'dired-display-file
  (kbd "h") 'dired-up-directory
  (kbd "l") 'dired-open-file ; use dired-find-file instead of dired-open.
  (kbd "m") 'dired-mark
  (kbd "t") 'dired-toggle-marks
  (kbd "u") 'dired-unmark
  (kbd "C") 'dired-do-copy
  (kbd "D") 'dired-do-delete
  (kbd "J") 'dired-goto-file
  (kbd "M") 'dired-do-chmod
  (kbd "O") 'dired-do-chown
  (kbd "P") 'dired-do-print
  (kbd "R") 'dired-do-rename
  (kbd "T") 'dired-do-touch
  (kbd "Y") 'dired-copy-filenamecopy-filename-as-kill ; copies filename to kill ring.
  (kbd "Z") 'dired-do-compress
  (kbd "+") 'dired-create-directory
  (kbd "-") 'dired-do-kill-lines
  (kbd "% l") 'dired-downcase
  (kbd "% m") 'dired-mark-files-regexp
  (kbd "% u") 'dired-upcase
  (kbd "* %") 'dired-mark-files-regexp
  (kbd "* .") 'dired-mark-extension
  (kbd "* /") 'dired-mark-directories
  (kbd "; d") 'epa-dired-do-decrypt
  (kbd "; e") 'epa-dired-do-encrypt)
;; (kbd "Q") 'quick-preview-at-point) ;; previews with sushi
;; Get file icons in dired
;; (add-hook 'dired-mode-hook 'all-the-icons-dired-mode)
;; With dired-open plugin, you can launch external programs for certain extensions
;; For example, I set all .png files to open in 'sxiv' and all .mp4 files to open in 'mpv'
(setq dired-open-extensions '(("gif" . "eog")
                              ("jpg" . "eog")
                              ("png" . "eog")
                              ("mkv" . "celluloid")
                              ("mp4" . "celluloid")))

Keybindings Within Dired With Peep-Dired-Mode Enabled

With peep-dired, you will get image previews as you go up/down with 'j' and 'k'

COMMAND DESCRIPTION KEYBINDING
peep-dired Toggle previews within dired SPC d p
peep-dired-next-file Move to next file in peep-dired-mode j
peep-dired-prev-file Move to previous file in peep-dired-mode k
(evil-define-key 'normal peep-dired-mode-map
 (kbd "j") 'peep-dired-next-file
 (kbd "k") 'peep-dired-prev-file)
(add-hook 'peep-dired-hook 'evil-normalize-keymaps)

Making deleted files go to trash can

(setq delete-by-moving-to-trash t
      trash-directory "~/.local/share/Trash/files/")

Clean up dired buffers while navigating away

;; (diredp-toggle-find-file-reuse-dir 1)
(setq dired-kill-when-opening-new-dired-buffer 1)

DOOM THEME

Setting the theme to doom-one. To try out new themes, I set a keybinding for counsel-load-theme with 'SPC h t'.

(use-package! base16-stylix-theme)
(require 'base16-stylix-theme)
(setq doom-theme 'base16-stylix)
;; (setq doom-theme 'doom-opera-light)
;; ;; (setq doom-theme 'doom-dark+)
;; (map! :leader
;;       :desc "Load new theme" "h t" #'counsel-load-theme)

EMMS

One of the media players available for Emacs is emms, which stands for Emacs Multimedia System. By default, Doom Emacs does not use 'SPC m p d',' so the format I use for these bindings is 'SPC a' plus 'key'.

COMMAND DESCRIPTION KEYBINDING
emms-playlist-mode-go Switch to the playlist buffer SPC a a
emms-pause Pause the track SPC a x
emms-stop Stop the track SPC a s
emms-previous Play previous track in playlist SPC a p
emms-next Play next track in playlist SPC a n
;; (emms-all)
;; (emms-default-players)
;; (emms-mode-line 1)
;; (emms-playing-time 1)
;; (setq emms-source-file-default-directory "~/Music/"
;;       emms-playlist-buffer-name "*Music*"
;;       emms-info-asynchronously t
;;       emms-source-file-directory-tree-function 'emms-source-file-directory-tree-find)
;; (map! :leader
;;       (:prefix ("m p d". "EMMS audio player")
;;        :desc "Go to emms playlist" "a" #'emms-playlist-mode-go
;;        :desc "Emms pause track" "x" #'emms-pause
;;        :desc "Emms stop track" "s" #'emms-stop
;;        :desc "Emms play previous track" "p" #'emms-previous
;;        :desc "Emms play next track" "n" #'emms-next))

EVALUATE ELISP EXPRESSIONS

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

COMMAND DESCRIPTION KEYBINDING
eval-buffer Evaluate elisp in buffer SPC e b
eval-defun Evaluate the defun containing or after point SPC e d
eval-expression Evaluate an elisp expression SPC e e
eval-last-sexp Evaluate elisp expression before point SPC e l
eval-region Evaluate elisp in region SPC e r
(map! :leader
      (:prefix ("e". "evaluate/EWW")
       :desc "Evaluate elisp in buffer" "b" #'eval-buffer
       :desc "Evaluate defun" "d" #'eval-defun
       :desc "Evaluate elisp expression" "e" #'eval-expression
       :desc "Evaluate last sexpression" "l" #'eval-last-sexp
       :desc "Evaluate elisp in region" "r" #'eval-region))

EWW

This is the Emacs Web Wowser, the builtin browser in Emacs. Below I set urls to open in a specific browser (eww) with browse-url-browser-function. By default, Doom Emacs does not use 'SPC e' for anything, so I choose to use the format 'SPC e' plus 'key' for these (I also use 'SPC e' for 'eval' keybindings). I chose to use 'SPC s w' for eww-search-words because Doom Emacs uses 'SPC s' for 'search' commands.

;; (setq browse-url-browser-function 'eww-browse-url)
(map! :leader
      :desc "Search web for text between BEG/END"
      "s w" #'eww-search-words
      (:prefix ("e" . "evaluate/EWW")
       :desc "Eww web browser" "w" #'eww
       :desc "Eww reload page" "R" #'eww-reload))

FONTS

Settings related to fonts within Doom Emacs:

  • 'doom-font' standard monospace font that defaults for most things in Emacs.
  • 'doom-variable-pitch-font' variable font which is useful in some Emacs plugins.
  • 'doom-big-font' used in doom-big-font-mode; useful for presentations.
  • 'font-lock-comment-face' for comments.
  • 'font-lock-keyword-face' for keywords with special significance like 'setq' in elisp.
(setq doom-unicode-font "Symbola")
(setq doom-font (font-spec :family "ComicShannsMono Nerd Font Mono" :size 18)
      doom-variable-pitch-font (font-spec :family "ComicShannsMono Nerd Font Mono" :size 18)
      doom-big-font (font-spec :family "ComicShannsMono Nerd Font Mono" :size 22))
(after! doom-themes
  (setq doom-themes-enable-bold t
        doom-themes-enable-italic t))
(custom-set-faces!
  '(bold :weight ultra-bold)
  '(font-lock-comment-face :slant italic)
  '(font-lock-keyword-face :slant italic))

FUNCTIONS

These are a collection of functions which I've snipped from multiple sources on the internet. Some are slightly modified for my preferences, but overall I'm not good enough with LISP to write my own functions yet.

Insert date

Some custom functions to insert the date. The function 'insert-todays-date' has three different formats:

  1. Just the keybinding without the universal argument prefix.
  2. With one universal argument prefix.
  3. With two universal argument prefixes.

The universal argument prefix is 'SPC-u' in Doom Emacs (C-u in standard GNU Emacs). The function 'insert-any-date' only outputs to one format, which is the same format as 'insert-todays-date' without a prefix.

COMMAND EXAMPLE OUTPUT KEYBINDING
dt/insert-todays-date 2021-11-19 SPC i d t
dt/insert-todays-date Friday, November 19, 2021 SPC u SPC i d t
dt/insert-any-date Friday, November 19, 2021 SPC i d a

NOTE Made by DT

(defun func/insert-todays-date (prefix)
  (interactive "P")
  (let ((format (cond
                 ((not prefix) "%Y-%m-%d")
                 ((equal prefix '(4)) "%A, %B %d, %Y"))))
    (insert (format-time-string format))))

(require 'calendar)
(defun func/insert-any-date (date)
  "Insert DATE using the current locale."
  (interactive (list (calendar-read-date)))
  (insert (calendar-date-string date)))

(map! :leader
      (:prefix ("i d" . "Insert date")
        :desc "Insert any date" "a" #'func/insert-any-date
        :desc "Insert todays date" "t" #'func/insert-todays-date))

Capture a task directly into a specific project

One important thing to point out here is that we're using 'file + head + olp' in the capture template so that we can drop the new task entry under the "Tasks" heading.

Works, but I'm unsure how to use it on my workflow, may be safe to delete it later.

NOTE made by SystemCrafters

(defun func/org-roam-capture-task ()
  (interactive)
  ;; Capture the new task, creating the project file if necessary
  (org-roam-capture-
   :node (org-roam-node-read nil)
   :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") #'my/org-roam-capture-task)

FLYCHECK

Configurations to add linting support to specific languages by integrating linters with flycheck.

(use-package! flycheck
  :config
  (flycheck-define-checker nix-statix
    "A syntax checker for Nix using Statix."
    :command ("statix" "check" source)
    :error-patterns
    ((warning line-start (file-name) ":" line ":" column
              ": " (message) line-end))
    :modes (nix-mode))

  (add-to-list 'flycheck-checkers 'nix-statix))

HUGO

Capture template for new hugo posts.

;; Populates only the EXPORT_FILE_NAME property in the inserted headline.
(with-eval-after-load 'org-capture
  (defun org-hugo-new-subtree-post-capture-template ()
    "Returns `org-capture' template string for new Hugo post.
  See `org-capture-templates' for more information."
    (let* ((title (read-from-minibuffer "Post Title: ")) ;Prompt to enter the post title
           (fname (org-hugo-slug title)))
      (mapconcat #'identity
                 `(
                   ,(concat "* TODO " title)
                   ":PROPERTIES:"
                   ,(concat ":EXPORT_FILE_NAME: " (format-time-string "%Y-%m-%d-") fname)
                   ":END:"
                   "%?\n") ;Place the cursor here finally
                 "\n"))))
;; org capture templates
(setq org-capture-templates
      '(
        ("h" ;`org-capture' binding + h
         "Hugo post"
         entry
         ;; It is assumed that below file is present in `org-directory'
         ;; and that it has a "Blog Ideas" heading. It can even be a
         ;; symlink pointing to the actual location of all-posts.org!
         (file+olp "/home/jawz/Development/Websites/portfolio/content-org/posts.org" "blog")
         (function org-hugo-new-subtree-post-capture-template))
        ))

LIGATURES

Set custom ligature symbols for different modes, which prettifies the Emacs experience.

Customizing ligatures, which replace strings with pretty symbols. They configure by mode.

;;;(after! org
  ;;;;; ⧗             ―               ﮸          λ ◁ ▷ ✧ ✦
  ;;;(appendq! +ligatures-extra-symbols
            ;;;`(:clock "⧗ "
              ;;;:circle ""
              ;;;:code ""
              ;;;:results "﮸"
              ;;;:shogi "⛊"
              ;;;:white_shogi "☖"
              ;;;:black_shogi "☗"
              ;;;:two_lines "⚏"
              ;;;;; :tags "    "
              ;;;:empty ""
              ;;;))
  ;;;(set-ligatures! 'org-mode
    ;;;;; :merge t
    ;;;;; :clock ":LOGBOOK:"
    ;;;:quote              "#+begin_quote"
    ;;;:name               "#+CAPTION:"
    ;;;:quote_end          "#+end_quote"
    ;;;:code               "#+begin_src"
    ;;;:code               "#+BEGIN_SRC"
    ;;;:src_block          "#+BEGIN:"
    ;;;:code               "#+end_src"
    ;;;:code               "#+END_SRC"
    ;;;:results            "#+RESULTS:"
    ;;;:results            "#+results:"
    ;;;;; :src_block_end     ":END:"
    ;;;;; :src_block_end     "#+END"
    ;;;;; :two_lines   ":PROPERTIES:"
    ;;;;; :black_shogi   "#+CATEGORY:"
    ;;;;; :black_shogi   "#+category:"
    ;;;;; :two_lines   "#+startup:"
    ;;;;; :two_lines   "#+STARTUP:"
    ;;;:empty              "#+title: "
    ;;;:empty              "#+TITLE: "
    ;;;;; :shogi "#+NAME:"
    ;;;;; :shogi "#+name:"
    ;;;;; :tags "keywords:"
    ;;;;; :black_shogi "#+roam_tags:"
    ;;;))

LINE SETTINGS

I set comment-line to 'SPC TAB TAB' which is a rather comfortable keybinding for me. The standard Emacs keybinding for comment-line is 'C-x C-;'. The other keybindings are for commands that toggle on/off line-related settings. Doom Emacs uses 'SPC t' for "toggle" commands, so I choose 'SPC t' plus 'key' for those bindings.

COMMAND DESCRIPTION KEYBINDING
comment-line Toggle commenting lines SPC TAB TAB
hl-line-mode Toggle line highlighting in current frame SPC t h
global-hl-line-mode Toggle line highlighting globally SPC t H
doom/toggle-line-numbers Toggle line numbers SPC t l
toggle-truncate-lines Toggle truncate lines SPC t t
(setq display-line-numbers-type t)
(map! :leader
      :desc "Comment or uncomment lines" "TAB TAB" #'comment-line
      (:prefix ("t" . "toggle")
       :desc "Toggle line numbers" "l" #'doom/toggle-line-numbers
       :desc "Toggle line highlight in frame" "h" #'hl-line-mode
       :desc "Toggle line highlight globally" "H" #'global-hl-line-mode
       :desc "Toggle truncate lines" "t" #'toggle-truncate-lines))

These are my default line display preferences.

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

LOAD-MODES

These settings make it so company modes load by default on specific file formats.

;; CONFIG
(require 'config-general-mode)
    (add-to-list 'auto-mode-alist '("\\.conf$" . config-general-mode))

MODELINE

The modeline is the bottom status bar that appears in Emacs windows. For more information on what is available to configure in the Doom modeline, check out: https://github.com/seagle0128/doom-modeline

(setq all-the-icons-scale-factor .8) ;; fixes the issue of rightmost characters not fitting.
(set-face-attribute 'mode-line nil :font "Iosevka Nerd Font-15")
(setq doom-modeline-height 30     ;; sets modeline height
      doom-modeline-bar-width 5   ;; sets right bar width
      doom-modeline-persp-name t  ;; adds perspective name to modeline
      doom-modeline-persp-icon t) ;; adds folder icon next to persp name

MOUSE SUPPORT

Adding mouse support in the terminal version of Emacs.

(xterm-mouse-mode 1)

OPEN SPECIFIC FILES

Keybindings to open files that I work with all the time using the find-file command, which is the interactive file search that opens with 'C-x C-f' in GNU Emacs or 'SPC f f' in Doom Emacs. These keybindings use find-file non-interactively since we specify exactly what file to open. The format I use for these bindings is 'SPC =' plus 'key' since Doom Emacs does not use 'SPC ='.

PATH TO FILE DESCRIPTION KEYBINDING
~/Documents/Notes/Agenda.org Edit agenda file SPC = a
~/.config/doom/config.org Edit doom config.org SPC = c
~/.config/doom/init.el Edit doom init.el SPC = i
~/.config/doom/packages.el Edit doom packages.el SPC = p
(map! :leader
      (:prefix ("=" . "open file")
       :desc "Edit agenda file" "a" #'(lambda () (interactive)
                                        (find-file
                                         "~/Documents/Notes/20220819130052-agenda.org"))
       :desc "Edit doom config.org" "c" #'(lambda () (interactive)
                                            (find-file
                                             "~/.config/doom/config.org"))
       :desc "Edit doom init.el" "i" #'(lambda () (interactive)
                                         (find-file "~/.config/doom/init.el"))
       :desc "Edit doom packages.el" "p" #'(lambda () (interactive)
                                             (find-file "~/.config/doom/packages.el"))))

LSP

When configured properly lsp-mode's performance is on par with mainstream LSP clients (e. g. VScode, Theia, etc). Here are steps to achieve optimal results.

(setq read-process-output-max (* 1024 1024)) ;; 1mb
(setq lsp-idle-delay 0.500)
(setq lsp-log-io nil) ; if set to true can cause a performance hit
;; c# LSP
(after! lsp-mode
    (setq lsp-csharp-server-path "/usr/bin/omnisharp"))

ORG MODE

I wrapped most of this block in (after! org). Without this, my settings might evaluate too early, which will result in my settings being overwritten by Doom's defaults. I have also enabled org-journal, org-superstar and org-roam by adding (+journal +pretty +roam2) to the org section of my Doom Emacs init.el.

These are my personal settings, heavily modified from DT's original config. For starters, I made it so org-agenda-files recursively feeds the agenda from .org files found on my Notes directory, also made it so logs go into drawers, and lastly customized the TODO keywords based on my personal preferences, these are settings overwrite the original org settings, and this require to run after org, so they can build upon the variables defined by the default configuration of Doom Emacs.

(after! org
  (setq org-directory "~/Documents/Notes/"
        org-agenda-files (directory-files-recursively
                          "~/Documents/Notes" "\\.org$")
        ;; org-default-notes-file (expand-file-name "Notes.org" org-directory)
        org-id-locations-file "~/Documents/Notes/.orgids"
        org-attach-id-dir "~/Documents/Notes/images"
        org-ellipsis " ▼ "
        org-superstar-headline-bullets-list '("◉" "●" "○" "◆" "●" "○" "◆")
        org-superstar-item-bullet-alist '((?+ . ?+) (?- . ?-))
        org-log-done 'time
        org-log-into-drawer t
        org-hide-emphasis-markers t
        org-todo-keywords
        '((sequence
           "TODO(t)" ; A task that needs doing & is ready to do
           "PROJ(p)" ; A project, which usually contains other tasks
           "ART(a)" ; Similar to PROJ but focused on drawing
           "IDEA(i)" ; Misc tasks, usually to elaborate on writing later
           "HOLD(h)" ; This task is paused/on hold because I'm a lazy fuck
           "|"
           "DONE(d)" ; Task succesfully completed
           "CANCELED(c)") ; Task was cancelled
          (sequence
           "[ ](T)" ; A task that needs doing
           "[-](S)" ; A task in progress
           "[?](H)" ; A task on hold
           "|"
           "[X](D)")) ;  A task completed
        org-todo-keyword-faces
        '(("[-]" . +org-todo-active)
          ("[?]" . +org-todo-onhold)
          ("HOLD" . +org-todo-onhold)
          ("ART" . +org-todo-project)
          ("IDEA" . +org-todo-project)
          ("PROJ" . +org-todo-project)
          ("CANCELED" . +org-todo-cancel)))
  (require 'org-habit))

Set font sizes for each header level in Org

You can set the Org heading levels to be different font sizes. So I choose to have level 1 headings to be 140% in height, level 2 to be 130%, etc. Other interesting things you could play with include adding :foreground color and/or :background color if you want to override the theme colors.

(custom-set-faces
  '(org-level-1 ((t (:inherit outline-1 :height 1.4))))
  '(org-level-2 ((t (:inherit outline-2 :height 1.3))))
  '(org-level-3 ((t (:inherit outline-3 :height 1.2))))
  '(org-level-4 ((t (:inherit outline-4 :height 1.1))))
  '(org-level-5 ((t (:inherit outline-5 :height 1.0))))
  '(org-document-title ((t (:inherit outline-1 :height 2.0))))
)

Org-Alert

This change makes it so org-alert uses libnotify for system notifications as well as update intervals.

;; (use-package org-alert
;;   :ensure t)
;; (setq alert-default-style 'libnotify
;;       org-alert-interval 3600)
;; ;; Auto start org-alert when emacs/daemon load
;; (org-alert-enable)

Org-Auto-Tangle

Allows you to add the option #+auto_tangle: t in your Org file so that it automatically tangles when you save the document.

(use-package org-auto-tangle
  :defer t
  :hook (org-mode . org-auto-tangle-mode))

Org-Babel

Load language support on org-babel, also map out org-babel-tangle.

(map! :leader
      :desc "Org babel tangle" "m B" #'org-babel-tangle)
;; (org-babel-do-load-languages
;;  'org-babel-load-languages
;;  '((R . t)
;;    (emacs-lisp . t)
;;    (nix . t)))

Org-Inlinetask

Enables a feature native to org-mode, which after a set amount of indentations, turns the header into a task, allowing for the insertion of TODO or PROJ without disrupting the indentation of the lines below it. https://github.com/amluto/org-mode/blob/master/lisp/org-inlinetask.el

(require 'org-inlinetask)
(setq org-inlinetask-min-level 9)

Org-Roam

First lines set up some preferences through variables, then it sets up some templates for dailies, and nodes.

COMMAND DESCRIPTION KEYBINDING
org-roam-find-file org roam find file SPC n r f
org-roam-insert org roam insert SPC n r i
org-roam-dailies-find-date org roam dailies find date SPC n r d d
org-roam-dailies-find-today org roam dailies find today SPC n r d t
org-roam-dailies-find-tomorrow org roam dailies find tomorrow SPC n r d m
org-roam-dailies-find-yesterday org roam dailies find yesterday SPC n r d y
(setq deft-directory "~/Documents/Notes/")
(use-package org-roam
  :ensure t
  :custom
  (org-roam-directory "~/Documents/Notes/")
  (org-roam-completion-everywhere t)
  (org-roam-dailies-capture-templates
      '(("d" "default" entry "* %<%I:%M %p>: %?"
         :if-new (file+head "%<%Y-%m-%d>.org" "#+title: %<%Y-%m-%d>\n"))))
  (org-roam-capture-templates
   '(("d" "default" plain
      "%?"
      :if-new (file+head "%<%Y%m%d%H%M%S>-${slug}.org" "#+title: ${title}\n")
      :unnarrowed t)
     ("l" "programming language" plain
      (file "/home/jawz/.config/doom/templates/programming.org")
      :if-new (file+head "%<%Y%m%d%H%M%S>-${slug}.org" "#+filetags: :programming:language:${title}:\n#+title: ${title}")
      :unnarrowed t)
     ("e" "political events" plain
      (file "/home/jawz/.config/doom/templates/events.org")
      :if-new (file+head "%<%Y%m%d%H%M%S>-${slug}.org" "#+filetags: :politics:conflicts:\n#+title: ${title}")
      :unnarrowed t)
     ("p" "project" plain
      "* PROJ ${title}\n%?\n* Tasks"
      :if-new (file+head "%<%Y%m%d%H%M%S>-${slug}.org" "#+category: ${title}\n#+filetags: :project:\n#+title: ${title}")
      :unnarrowed t)
     ))
  :bind()
  :bind-keymap()
  :config
  (org-roam-db-autosync-mode))
(setq completion-ignore-case t)
(set-file-template! "~/Documents/Notes/.+\\.org$" 'org-mode :ignore t)

Org-Roam-UI

This is a superior (and interactive) visualizer for org-roam graph. https://github.com/org-roam/org-roam-ui

(use-package! websocket
    :after org-roam)

(use-package! org-roam-ui
    :after org-roam ;; or :after org
;;         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 nil))

Org-Transclusion

Org-transclusion lets you insert a copy of text content via a file link or ID link within an Org file. It lets you have the same content present in different buffers at the same time without copy-and-pasting it. Edit the source of the content, and you can refresh the transcluded copies to the up-to-date state. Org-transclusion keeps your files clear of the transcluded copies, leaving only the links to the original content. https://github.com/nobiot/org-transclusion

COMMAND DESCRIPTION KEYBINDING
org-transclusion-add Add transclusion block SPC n r a
org-transclusion-mode Toggle transclusion mode SPC n r t
(use-package! org-transclusion
  :after org
  :init
  (map!
   :map global-map "<f12>" #'org-transclusion-add
   :leader
   (:prefix ("n r" . "toggle")
    :desc "Org Transclussion Add" "a" #'org-transclusion-add
    :desc "Org Transclusion Mode" "t" #'org-transclusion-mode)))

OTHER SETTINGS

These are some personal settings, and other fixes.

Disable persistent undo

Uses undo-tree instead of undo-fu, which is a little less stable, but offers branching undo history and a visualizer for navigating it.

  • If using +tree

    (after! undo-tree
    (setq undo-tree-auto-save-history nil))
  • Else

    ;; (remove-hook 'undo-fu-mode-hook #'global-undo-fu-session-mode)

User information

(setq user-full-name "Danilo Reyes"
      user-mail-address "CaptainJawZ@outlook.com")

Variables

Custom set variables, I should note that I don't know what git commit major mode does, but flycheck is for minimizing errors on python scripts for long line length.

(custom-set-variables
 '(flycheck-flake8-maximum-line-length 88)
 '(safe-local-variable-values '((git-commit-major-mode . git-commit-elisp-text-mode))))

REGISTERS

Emacs registers are compartments where you can save text, rectangles and positions for later use. Once you save text or a rectangle in a register, you can copy it into the buffer once or multiple times; once you save a position in a register, you can jump back to that position once or multiple times. The default GNU Emacs keybindings for these commands (with the exception of counsel-register) involves 'C-x r' followed by one or more other keys. I wanted to make this a little more user friendly, and since I am using Doom Emacs, I choose to replace the 'C-x r' part of the key chords with 'SPC r'.

COMMAND DESCRIPTION KEYBINDING
copy-to-register Copy to register SPC r c
frameset-to-register Frameset to register SPC r f
insert-register Insert contents of register SPC r i
jump-to-register Jump to register SPC r j
list-registers List registers SPC r l
number-to-register Number to register SPC r n
counsel-register Interactively choose a register SPC r r
view-register View a register SPC r v
window-configuration-to-register Window configuration to register SPC r w
increment-register Increment register SPC r +
point-to-register Point to register SPC r SPC
(map! :leader
      (:prefix ("r" . "registers")
       :desc "Copy to register" "c" #'copy-to-register
       :desc "Frameset to register" "f" #'frameset-to-register
       :desc "Insert contents of register" "i" #'insert-register
       :desc "Jump to register" "j" #'jump-to-register
       :desc "List registers" "l" #'list-registers
       :desc "Number to register" "n" #'number-to-register
       :desc "Interactively choose a register" "r" #'counsel-register
       :desc "View a register" "v" #'view-register
       :desc "Window configuration to register" "w" #'window-configuration-to-register
       :desc "Increment register" "+" #'increment-register
       :desc "Point to register" "SPC" #'point-to-register))

SPELL

This will disable Proselint from running inside code blocks.

(defadvice! fixed-flycheck-proselint-parse-errors-a (output checker buffer)
  :override #'flycheck-proselint-parse-errors
  (delq
   nil (mapcar (lambda (err)
                 (let-alist err
                   (and (or (not (derived-mode-p 'org-mode))
                            (save-excursion (goto-char .start)
                                            (not (org-in-src-block-p))))
                        (flycheck-error-new-at-pos
                         .start
                         (pcase .severity
                           (`"suggestion" 'info)
                           (`"warning"    'warning)
                           (`"error"      'error)
                           (_             'error))
                         .message
                         :id .check
                         :buffer buffer
                         :checker checker
                         :end-pos .end))))
               (let-alist (car (flycheck-parse-json output))
                 .data.errors))))

SPLITS

I set splits to default to opening on the right using 'prefer-horizontal-split'. I set a keybinding for 'clone-indirect-buffer-other-window' for when I want to have the same document in two splits. The text of the indirect buffer is always identical to the text of its base buffer; changes made by editing either one are visible immediately in the other. But in all other respects, the indirect buffer and its base buffer are separate. For example, I can fold one split but the other remains unfolded.

(defun prefer-horizontal-split ()
  (set-variable 'split-height-threshold nil t)
  (set-variable 'split-width-threshold 40 t)) ; make this as low as needed
(add-hook 'markdown-mode-hook 'prefer-horizontal-split)
(map! :leader
      :desc "Clone indirect buffer other window" "b c" #'clone-indirect-buffer-other-window)

TWITTER

Needed to login on twitter.

(setq twittering-allow-insecure-server-cert t)

WINNER MODE

Winner mode comes with GNU Emacs since version 20. This is a global minor mode and, when activated, it allows you to “undo” (and “redo”) changes in the window configuration with the key commands 'SCP w <left>' and 'SPC w <right>'.

(map! :leader
      (:prefix ("w" . "window")
       :desc "Winner redo" "<right>" #'winner-redo
       :desc "Winner undo" "<left>" #'winner-undo))

ZAP TO CHAR

Emacs provides a 'zap-to-char' command that kills from the current point to a character. It bounds to 'M-z' in standard GNU Emacs but since Doom Emacs uses 'SPC' as its leader key and does not have 'SPC z' binding to anything, it just makes since to use it for 'zap-to-char'. Note that 'zap-to-char' can combine with the universal argument 'SPC u' to modify its behaviour. Examples of 'zap-to-char' usage listed in the table below:

KEYBINDING WHAT IS DOES
SPC z e deletes all chars to the next occurrence of 'e'
SPC u 2 SPC z e deletes all chars to the second occurrence of 'e'
SPC u - SPC z e deletes all chars to the previous occurrence of 'e'
SPC u -2 SPC z e deletes all chars to the fourth previous occurrence of 'e'
SPC u 1 0 0 SPC u SPC z e deletes all chars to the 100th occurrence of 'e'

TIP The universal argument (SPC u) can only take a single integer by default. If you need to use a multi-digit number (like 100 in the last example in the table above), then you must terminate the universal argument with another 'SPC u' after typing the number.

'zap-up-to-char' is an alternative command that does not zap the char specified. It bounds to 'SPC Z'. It can also combine in conjunction with the universal argument 'SPC u' in similar fashion to the 'zap-to-char' examples above.

NOTE Vim (evil mode) has similar functionality builtin. You can delete to the next occurrence of 'e' by using 'dte' in normal. To delete to the next occurrence of 'e' including the 'e', then you would use 'dfe'. And you can modify 'dt' and 'df' by prefixing them with numbers, so '2dte' would delete to the second occurrence of 'e'.

(map! :leader
      :desc "Zap to char" "z" #'zap-to-char
      :desc "Zap up to char" "Z" #'zap-up-to-char)