doom/config.org
J S f5caccd7f7
feat[lsp,org,cite]: Added better citation icons
I added some snazzy icons to citar.
Corrected several org-latex classes to avoid hyperlink highlights.
Added (potentially) better LSP settings with syntax flags
2023-10-30 13:07:22 -04:00

39 KiB

Doom-emacs config

Welcome to my configuration! I hope you enjoy your time here :) It's not all very well documented, but I have done my best to split everything into a logical order. Perhaps in 10 years I will still be using it, but who knows.

Task List

TODO Reorganize into use-cases rather than packages

Setting Basics

(setq tab-always-indent t)
(setq org-roam-directory "~/org/")


(setq user-full-name "Judah Sotomayor"
      user-mail-address "")

Theme and Font

Set the theme. Use something dark I also prefer relative line numbers because of evil mode Relative line numbers don't work, because of foling in Org-mode.

(setq doom-theme 'doom-dark+)
(setq doom-font (font-spec :family "Hack Nerd Font Mono" :size 16 :weight 'medium))
(setq auto-save-default nil) ;I don't like autosaving. Let me do it myself.

Doom splash screen

I really don't like the widgets, and I think it takes longer to load so I get rid of them

(remove-hook '+doom-dashboard-functions #'doom-dashboard-widget-shortmenu)
(remove-hook '+doom-dashboard-functions #'doom-dashboard-widget-footer)

Set a sweet splash image

(setq fancy-splash-image (concat doom-private-dir "emacs.png"))

Evil configuration

I want a non-ESC way to get back to normal mode:

(map! :desc "Switch to normal mode" :i "C-c" #'evil-normal-state)

Terminal setup

I like to just use bash:

(defun bash ()
  (interactive)
  (term "/bin/bash"))
(map!
      :desc "Start a bash shell"
      "<f6>" #'bash)

I don't like the modeline in the terminal.

(add-hook 'term-mode-hook 'hide-mode-line-mode)

Sage-math

(use-package! sage-shell-mode
  :defer)

;; Ob-sagemath supports only evaluating with a session.
(setq org-babel-default-header-args:sage '((:session . t)
                                           (:results . "output")))

;; C-c c for asynchronous evaluating (only for SageMath code blocks).
(with-eval-after-load "org"
  (define-key org-mode-map (kbd "C-c c") 'ob-sagemath-execute-async))

I like to have a shortcut for calc as well, for simpler calculations

(map! :leader
      :desc "The Emacs Calculator"
      "C" #'calc)

Beancount

FavaGTK   outdated

I want to launch favagtk more easily. Let's do that here:

(defun fava ()
  (interactive)
  (async-shell-command "flatpak run org.gnome.gitlab.johannesjh.favagtk"))
(map! :leader
 :desc "Start favagtk"
 "r b" #'fava)

Graphing Applications

Mermaid.js

Mermaid.js requires the mmcli executable from npm. Mermaid is a tool that allows you to graph many kinds of entities:

  • Relationship diagrams
  • Flowcharts
  • Gantt diagrams

There's other kinds too. The package on ELPA is perfect. Needs no config, fits right in with Babel.

(use-package! ob-mermaid)

SVGBob

SVGBob is an ASCII art renderer. It can do all kinds of nifty things with just a few basic .——./\

(use-package! ob-svgbob)
(setq org-svgbob-executable "svgbob_cli")

(setq org-babel-svgbob--parameters
  '(:background transparent
    ))

Fun Stuff

Useful Functions

Get the date from the shell

I want to grab the current date and put it in the buffer. Because I sometimes use Fish or another shell, it's good to make sure bash is running the command using the

`-c`
flag.

(defun current-date () (interactive)
    (shell-command-to-string " bash -c 'echo -n $(date +%Y-%m-%d)'"))
 (defun insert-current-date () (interactive)
    (insert (current-date)))

(map! :leader
      :desc "Insert the current date into the buffer"
      "i d" #'insert-current-date)

Creating Diagrams and graphs

TODO set default values using org-babel's features for that.

Securing Sensitive Files

Age.el

(use-package! age
  :ensure t
  :demand t
  :custom
  (age-program "age")
  (age-default-identity "~/.age/personal")
  (age-default-recipient "~/.age/personal.pub")
  :config
  (age-file-enable))

Org-mode security settings

These mostly concern limiting evaluation of code-blocks without confirmation. The final two lines concern local variables, which may try to evaluate code.

Emacs has better default values now, so it will ask to evaluate local variables.

(setq org-confirm-babel-evaluate t)
(setq org-link-shell-confirm-function t)
(setq org-link-elisp-confirm-function t)
(setq enable-local-variables t)
(setq enable-local-eval 'maybe)

Org-mode for a great todo list

Making the Agenda features more efficient

(dolist (file (org-roam-list-files))
  (message "processing %s" file)
  (with-current-buffer (or (find-buffer-visiting file)
                           (find-file-noselect file))
    (vulpea-project-update-tag)
    (save-buffer)))

Only include files with the hastodos tag. This section is contributed from d12frosted and use his vulpea.el package's functions. I ripped out the essentials because I don't want all the other stuff in that package.

(after! org-roam
(defun vulpea-project-p ()
  "Return non-nil if current buffer has any todo entry.
TODO entries marked as done are ignored, meaning the this
function returns nil if current buffer contains only completed
tasks."
  (seq-find                                 ; (3)
   (lambda (type)
     (eq type 'todo))
   (org-element-map                         ; (2)
       (org-element-parse-buffer 'headline) ; (1)
       'headline
     (lambda (h)
       (org-element-property :todo-type h)))))

(defun vulpea-project-update-tag ()
    "Update PROJECT tag in the current buffer."
    (when (and (not (active-minibuffer-window))
               (vulpea-buffer-p))
      (save-excursion
        (goto-char (point-min))
        (let* ((tags (vulpea-buffer-tags-get))
               (original-tags tags))
          (if (vulpea-project-p)
              (setq tags (cons "hastodos" tags))
            (setq tags (remove "hastodos" tags)))

          ;; cleanup duplicates
          (setq tags (seq-uniq tags))

          ;; update tags if changed
          (when (or (seq-difference tags original-tags)
                    (seq-difference original-tags tags))
            (apply #'vulpea-buffer-tags-set tags))))))

(defun vulpea-buffer-p ()
  "Return non-nil if the currently visited buffer is a note."
  (and buffer-file-name
       (string-prefix-p
        (expand-file-name (file-name-as-directory org-roam-directory))
        (file-name-directory buffer-file-name))))

(defun vulpea-project-files ()
    "Return a list of note files containing 'hastodos' tag." ;
    (seq-uniq
     (seq-map
      #'car
      (org-roam-db-query
       [:select [nodes:file]
        :from tags
        :left-join nodes
        :on (= tags:node-id nodes:id)
        :where (like tag (quote "%\"hastodos\"%"))]))))

(defun vulpea-agenda-files-update (&rest _)
  "Update the value of `org-agenda-files'."
  (setq org-agenda-files (vulpea-project-files)))

(add-hook 'find-file-hook #'vulpea-project-update-tag)
(add-hook 'before-save-hook #'vulpea-project-update-tag)

(advice-add 'org-agenda :before #'vulpea-agenda-files-update)
(advice-add 'org-todo-list :before #'vulpea-agenda-files-update)

;; functions borrowed from `vulpea' library
;; https://github.com/d12frosted/vulpea/blob/6a735c34f1f64e1f70da77989e9ce8da7864e5ff/vulpea-buffer.el

(defun vulpea-buffer-tags-get ()
  "Return filetags value in current buffer."
  (vulpea-buffer-prop-get-list "filetags" "[ :]"))

(defun vulpea-buffer-tags-set (&rest tags)
  "Set TAGS in current buffer.
If filetags value is already set, replace it."
  (if tags
      (vulpea-buffer-prop-set
       "filetags" (concat ":" (string-join tags ":") ":"))
    (vulpea-buffer-prop-remove "filetags")))

(defun vulpea-buffer-tags-add (tag)
  "Add a TAG to filetags in current buffer."
  (let* ((tags (vulpea-buffer-tags-get))
         (tags (append tags (list tag))))
    (apply #'vulpea-buffer-tags-set tags)))

(defun vulpea-buffer-tags-remove (tag)
  "Remove a TAG from filetags in current buffer."
  (let* ((tags (vulpea-buffer-tags-get))
         (tags (delete tag tags)))
    (apply #'vulpea-buffer-tags-set tags)))

(defun vulpea-buffer-prop-set (name value)
  "Set a file property called NAME to VALUE in buffer file.
If the property is already set, replace its value."
  (setq name (downcase name))
  (org-with-point-at 1
    (let ((case-fold-search t))
      (if (re-search-forward (concat "^#\\+" name ":\\(.*\\)")
                             (point-max) t)
          (replace-match (concat "#+" name ": " value) 'fixedcase)
        (while (and (not (eobp))
                    (looking-at "^[#:]"))
          (if (save-excursion (end-of-line) (eobp))
              (progn
                (end-of-line)
                (insert "\n"))
            (forward-line)
            (beginning-of-line)))
        (insert "#+" name ": " value "\n")))))

(defun vulpea-buffer-prop-set-list (name values &optional separators)
  "Set a file property called NAME to VALUES in current buffer.
VALUES are quoted and combined into single string using
`combine-and-quote-strings'.
If SEPARATORS is non-nil, it should be a regular expression
matching text that separates, but is not part of, the substrings.
If nil it defaults to `split-string-default-separators', normally
\"[ \f\t\n\r\v]+\", and OMIT-NULLS is forced to t.
If the property is already set, replace its value."
  (vulpea-buffer-prop-set
   name (combine-and-quote-strings values separators)))

(defun vulpea-buffer-prop-get (name)
  "Get a buffer property called NAME as a string."
  (org-with-point-at 1
    (when (re-search-forward (concat "^#\\+" name ": \\(.*\\)")
                             (point-max) t)
      (buffer-substring-no-properties
       (match-beginning 1)
       (match-end 1)))))

(defun vulpea-buffer-prop-get-list (name &optional separators)
  "Get a buffer property NAME as a list using SEPARATORS.
If SEPARATORS is non-nil, it should be a regular expression
matching text that separates, but is not part of, the substrings.
If nil it defaults to `split-string-default-separators', normally
\"[ \f\t\n\r\v]+\", and OMIT-NULLS is forced to t."
  (let ((value (vulpea-buffer-prop-get name)))
    (when (and value (not (string-empty-p value)))
      (split-string-and-unquote value separators))))

(defun vulpea-buffer-prop-remove (name)
  "Remove a buffer property called NAME."
  (org-with-point-at 1
    (when (re-search-forward (concat "\\(^#\\+" name ":.*\n?\\)")
                             (point-max) t)
      (replace-match ""))))

    (setq org-agenda-files (vulpea-project-files)))

Basic settings

    (setq org-log-done 'time)
    (after! org-mode
        (setq org-log-done 'time)
        (add-to-list 'org-tags-exclude-from-inheritance "hastodos")
        (setq org-hide-emphasis-markers nil))

    (setq org-directory "~/org/")
    (setq org-roam-directory org-directory)

Appearances

Deprecated: TODO Keywords

I like to have a few different todo keywords for different sorts of activities. Purchasing todos:

(setq org-todo-keywords
      '((sequence "PROJ(p)" "|" "COMPLETE")
        (type "TICKLE")
        (type "DELE")
        (type "WAIT")
        (sequence   "TODO(t)"  "|"  "DONE")
        (sequence "DELEGATED" "VERIFY" "|" "DONE")
        (sequence "BUY(b)" "|" "BOUGHT")
        ))
(setq org-todo-keyword-faces
      '(("TODO" . "salmon1")
        ("START" . "spring green" )
        ("DELE" . "gold")
        ("TICKLE" . "magenta")
        ("WAIT" . "gold")
        ("PROJ" . "deep sky blue")))

These settings aren't very useful for me, as I like default colors and keywords.

Deprecated: Settings for org-modern

(setq org-modern-todo-faces
      '(("START" :background "spring green" :foreground "black")
        ("DELE" :background "gold" :foreground "black")
        ("WAIT" :background "gold" :foreground "black")
        ("PROJ" :background "deep sky blue" :foreground "black")
        ("TICKLE" :background "magenta" :foreground "black")))

(setq org-modern-priority-faces
      '((?A :background "salmon1" :foreground "black")
        (?B :background "gold" :foreground "black")
        (?C :background "spring green" :foreground "black")))

I currently have org-modern stripped out of my config. I probably won't need this again, but in case I do I want all my preferences to be there.

Images Preferences

We want to show images when loading a file, and also after evaluating code blocks.

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

;; Show images after evaluating code blocks.
(add-hook 'org-babel-after-execute-hook 'org-display-inline-images)

Org-drill

Set some good keybinds for quick access:

(use-package! org-drill
  :defer nil
  )

  (map! :leader
        :desc "Start org-drill"
        "d d" #'org-drill-directory)

  (map! :leader
        :desc "Start org-drill in cram mode"
        "d c" #'org-drill-cram)

ob-lilypond

(use-package! ob-lilypond)
(setq ly-arrange-mode t)

org-edna

Edna allows better dependency handling for todos and the like.

(use-package! org-edna)
(org-edna-mode)

Org-habit

 (use-package org-habit
	:custom
	(org-habit-graph-column 1)
	(org-habit-preceding-days 10)
	(org-habit-following-days 1)
	(org-habit-show-habits-only-for-today nil))

 (use-package! org-heatmap
	:after (org)
	:config
	(org-heatmap-mode))

Org-archive with structure

Many thanks to Mark Edigmar's Gist

Keymaps

(map! :leader
      :desc "Export to html and diplay with eww"
      :n "m A" #'org-archive-subtree-default)

Source

(require 'org-archive)

; Set the function to use for org-archive-default  (C-c C-x C-a)
; (setq org-archive-location (concat org-directory "/archive/%s_archive::"))
; (setq org-archive-location "archive/archived_%s::")

(setq org-archive-location "~/org/archive.org")
(setq org-archive-location (concat org-directory "/archive.org::"))
; unmap org-archive-subtree

; select command to execute via org-archive-subtree-default (C-c C-x C-a)
(setq org-archive-default-command 'org-archive-subtree-hierarchical)

(defun line-content-as-string ()
  "Returns the content of the current line as a string"
  (save-excursion
    (beginning-of-line)
    (buffer-substring-no-properties
     (line-beginning-position) (line-end-position))))

(defun org-child-list (&optional top-level)
  "This function returns all children of a heading as a list. "
  (interactive)
  (save-excursion
    ;; this only works with org-version > 8.0, since in previous
    ;; org-mode versions the function (org-outline-level) returns
    ;; gargabe when the point is not on a heading.
    (unless top-level
        (if (= (org-outline-level) 0)
            (outline-next-visible-heading 1)
        (org-goto-first-child)))
    (let ((child-list (list (line-content-as-string))))
      (while (org-goto-sibling)
        (setq child-list (cons (line-content-as-string) child-list)))
      child-list)))

(defun fa/org-struct-subtree ()
  "This function returns the tree structure in which a subtree belongs as a list."
  (interactive)
  (let ((archive-tree nil))
    (save-excursion
      (while (org-up-heading-safe)
        (let ((heading
               (buffer-substring-no-properties
                (line-beginning-position) (line-end-position))))
          (if (eq archive-tree nil)
              (setq archive-tree (list heading))
            (setq archive-tree (cons heading archive-tree))))))
    archive-tree))

(defun org-archive-subtree-hierarchical ()
  "This function archives a subtree hierarchical"
  (interactive)
  (let ((org-tree (fa/org-struct-subtree))
        (source-buffer (current-buffer))
        (file (abbreviate-file-name
                   (or (buffer-file-name (buffer-base-buffer))
                       (error "No file associated to buffer")))))
    (save-excursion
      (setq location (org-archive--compute-location
                (or (org-entry-get nil "ARCHIVE" 'inherit)
                    org-archive-location))
            afile (car location)
            heading (cdr location)
            infile-p (equal file (abbreviate-file-name (or afile ""))))
      (unless afile
        (error "Invalid `org-archive-location'"))
      (if (not (equal heading ""))
          (progn
            (setq org-tree (cons heading
                               (mapcar (lambda (s) (concat "*" s)) org-tree)))
            (org-demote-subtree)))
      (if (> (length afile) 0)
        (progn
          (setq newfile-p (not (file-exists-p afile))
                visiting (find-buffer-visiting afile)
                target-buffer (or visiting (find-file-noselect afile))))
        (progn
          (setq target-buffer (current-buffer))))
      (unless target-buffer
        (error "Cannot access file \"%s\"" afile))
      (org-cut-subtree)
      (set-buffer target-buffer)
      (setq ind-target-buffer (clone-indirect-buffer nil nil))
      (set-buffer ind-target-buffer)
      (org-mode)
      (goto-char (point-min))

      ; simplified version of org-complex-heading-regexp-format
	  (setq my-org-complex-heading-regexp-format
	      (concat "^"
		      "\\(%s\\)"
		      "\\(?: *\\[[0-9%%/]+\\]\\)*"
		      "\\(?:[ \t]+\\(:[[:alnum:]_@#%%:]+:\\)\\)?"
		      "[ \t]*$"))
      (setq top-level-p t)
      (while (not (equal org-tree nil))
        (let ((child-list (org-child-list top-level-p))
              (re (format my-org-complex-heading-regexp-format (regexp-quote (car org-tree))))
             )
          (if (member "______FOUND_MATCH" (mapcar (lambda (s) (replace-regexp-in-string re "______FOUND_MATCH" s)) child-list))
              (progn
                (re-search-forward re nil t)
                (setq org-tree (cdr org-tree)))
            (progn
              (if (not top-level-p) (newline))
              (org-insert-struct org-tree)
              (setq org-tree nil))))
        (setq top-level-p nil))
      (end-of-buffer)
      (newline)
      (org-yank)
      ;; Kill the indirect buffer, returning the current buffer to the direct target buffer
      (kill-buffer ind-target-buffer)
      ;; Save and kill the target buffer, if it is not the source buffer.
      (when (not (eq source-buffer target-buffer))
            (save-buffer target-buffer)
            (kill-buffer target-buffer))
      ;; ensure font-lock and indentation are normal
      (set-buffer source-buffer)
      (org-restart-font-lock)
      (org-indent-mode t)
      (message "Subtree archived %s"
               (concat "in file: " (abbreviate-file-name afile))))))

(defun org-insert-struct (struct)
  "TODO"
  (interactive)
  (when struct
    (insert (car struct))
    (if  (not (equal (length struct) 1))
        (newline))
    (org-insert-struct (cdr struct))))

Website

Capture template

(setq templates/post-capture-props "#+date: [%<%Y-%m-%d %a>]\n#+lastmod:\n#+categories[]:\n#+tags[]:\n#+images[]: ")
(setq templates/post-capture-title "#+TITLE: ${title}\n")
(setq templates/post-capture-template (concat templates/post-capture-title templates/post-capture-props))

Images

(setq org-preview-latex-image-directory (concat org-directory (file-name-as-directory "images/latexsnip")))

Hugo base directory

(setq org-hugo-base-dir (concat org-directory (file-name-as-directory "website")))
(setq org-hugo-default-section-directory "posts")

Crafting a Writing Environment

For writing I like to automate as much as possible. This means creating an environment that does citations and such for me.

Export settings

Ox-latex

(after! org
  ;; Import ox-latex to get org-latex-classes and other funcitonality
  ;; for exporting to LaTeX from org
  (use-package! ox-latex
    :init
    :config

    (setq org-latex-with-hyperref nil) ;; stop org adding hypersetup{author..} to latex export
    ;; (setq org-latex-prefer-user-labels t)
    (setq org-latex-logfiles-extensions
          (quote ("lof" "lot" "tex~" "aux" "idx" "log" "out" "toc" "nav" "snm" "vrb" "dvi" "fdb_latexmk" "blg" "brf" "fls" "entoc" "ps" "spl" "bbl" "xmpi" "run.xml" "bcf" "acn" "acr" "alg" "glg" "gls" "ist")))

    (unless (boundp 'org-latex-classes)
      (setq org-latex-classes nil))))

Lualatex as PDF Processor

I've found that lualatex does a good job processing PDFs. $hi$

(after! ox-latex
  (setq org-latex-pdf-process
  '("lualatex --output-directory=/home/user/Documents -shell-escape -interaction nonstopmode %f"
    "lualatex --output-directory=/home/user/Documents -shell-escape -interaction nonstopmode %f"))
  )

$x + 1 = 3$

luamagick
(setq-default org-html-with-latex `dvisvgm)



(unless (boundp 'org-latex-classes)
  (setq org-latex-classes nil))

(add-to-list 'org-latex-classes
             '("ethz"
               "\\documentclass[a4paper,11pt,titlepage]{memoir}
    \\usepackage[utf8]{inputenc}
    \\usepackage[T1]{fontenc}
    \\usepackage{fixltx2e}
    \\usepackage{graphicx}
    \\usepackage{longtable}
    \\usepackage{float}
    \\usepackage{wrapfig}
    \\usepackage{rotating}
    \\usepackage[normalem]{ulem}
    \\usepackage{amsmath}
    \\usepackage{textcomp}
    \\usepackage{marvosym}
    \\usepackage{wasysym}
    \\usepackage{amssymb}
    \\usepackage[hidelinks]{hyperref}
    \\usepackage{mathpazo}
    \\usepackage{color}
    \\usepackage{enumerate}
    \\definecolor{bg}{rgb}{0.95,0.95,0.95}
    \\tolerance=1000
          [NO-DEFAULT-PACKAGES]
          [PACKAGES]
          [EXTRA]
    \\linespread{1.1}
    \\hypersetup{pdfborder=0 0 0}"
               ("\\chapter{%s}" . "\\chapter*{%s}")
               ("\\section{%s}" . "\\section*{%s}")
               ("\\subsection{%s}" . "\\subsection*{%s}")
               ("\\subsubsection{%s}" . "\\subsubsection*{%s}")
               ("\\paragraph{%s}" . "\\paragraph*{%s}")
               ("\\subparagraph{%s}" . "\\subparagraph*{%s}")))


(add-to-list 'org-latex-classes
             '("article"
               "\\documentclass[11pt,a4paper]{article}
    \\usepackage[utf8]{inputenc}
    \\usepackage[T1]{fontenc}
    \\usepackage{fixltx2e}
    \\usepackage{graphicx}
    \\usepackage{longtable}
    \\usepackage{float}
    \\usepackage{wrapfig}
    \\usepackage{rotating}
    \\usepackage[normalem]{ulem}
    \\usepackage{amsmath}
    \\usepackage{textcomp}
    \\usepackage{marvosym}
    \\usepackage{wasysym}
    \\usepackage{amssymb}
    \\usepackage[hidelinks]{hyperref}
    \\usepackage{mathpazo}
    \\usepackage{color}
    \\usepackage{enumerate}
    \\definecolor{bg}{rgb}{0.95,0.95,0.95}
    \\tolerance=1000
          [NO-DEFAULT-PACKAGES]
          [PACKAGES]
          [EXTRA]
    \\linespread{1.1}
    \\hypersetup{pdfborder=0 0 0}"
               ("\\section{%s}" . "\\section*{%s}")
               ("\\subsection{%s}" . "\\subsection*{%s}")
               ("\\subsubsection{%s}" . "\\subsubsection*{%s}")
               ("\\paragraph{%s}" . "\\paragraph*{%s}")))


(add-to-list 'org-latex-classes '("ebook"
                                  "\\documentclass[11pt, oneside]{memoir}
    \\setstocksize{9in}{6in}
    \\settrimmedsize{\\stockheight}{\\stockwidth}{*}
    \\setlrmarginsandblock{2cm}{2cm}{*} % Left and right margin
    \\setulmarginsandblock{2cm}{2cm}{*} % Upper and lower margin
    \\checkandfixthelayout
    % Much more laTeX code omitted
    "
                                  ("\\chapter{%s}" . "\\chapter*{%s}")
                                  ("\\section{%s}" . "\\section*{%s}")
                                  ("\\subsection{%s}" . "\\subsection*{%s}")))
mcdowellcv \documentclass[]{mcdowellcv}

Fixing dvipng image handling

(defun +org-refresh-latex-images-previews-h ()
  (dolist (buffer (doom-buffers-in-mode 'org-mode (buffer-list)))
    (with-current-buffer buffer
      (+org--toggle-inline-images-in-subtree (point-min) (point-max) 'refresh)
      (unless (eq org-latex-preview-default-process 'dvisvgm)
        (org-clear-latex-preview (point-min) (point-max))
        (org--latex-preview-region (point-min) (point-max))))))

(add-hook 'doom-load-theme-hook #'+org-refresh-latex-images-previews-h)

Export Function

(defun eww-open-this-file ()
       (set 'directory (file-name-directory buffer-file-name))
       (set 'filename (file-name-sans-extension buffer-file-name))
       (set 'extension ".html")
       (set 'filename (format "%s%s" filename extension))
       (eww-open-file filename)
       (evil-window-left)
)

(defun org-export-and-open-eww ()
    "Export current file to html and open in eww"
    (interactive)

    (org-html-export-to-html)
    (if (equal (file-name-extension buffer-file-name) "org")
         (eww-open-this-file)
      (message "Failed")
    )
)

We'll want a handy shortcut for this.

            (map! :leader
                    :desc "Export to html and diplay with eww"
                    "r E" #'org-export-and-open-eww)
/home/user/.config/doom/

Automatic Citations with citar and org-cite

Citar is a sweet little package for managing citations. We want a general bibliography file, a styles directory, and a default set of styles.

Citar setup

First of all, we must configure citar.

(use-package! citar
  :ensure t
  :demand t
  :custom
  (citar-bibliography "~/org/references.bib")
  (citar-file-note-extensions '(".org"))
  (org-cite-global-bibliography '("~/org/references.bib"))

  (org-cite-csl-styles-dir
   (expand-file-name "~/Zotero/styles/"))
  (org-cite-export-processors
    '((t . (csl "apa.csl")) ))

  :hook
  (LaTeX-mode . citar-capf-setup)
  (org-mode . citar-capf-setup))
(citar-org-roam-mode)

Icons for some prettification

(after! citar
    (setq citar-indicator-files-icons
      (citar-indicator-create
       :symbol (nerd-icons-faicon
                "nf-fa-file_o"
                :face 'nerd-icons-green
                :v-adjust -0.1)
       :function #'citar-has-files
       :padding "  " ; need this because the default padding is too low for these icons
       :tag "has:files"))

    (setq citar-indicator-links-icons
      (citar-indicator-create
       :symbol (nerd-icons-faicon
                "nf-fa-link"
                :face 'nerd-icons-orange
                :v-adjust 0.01)
       :function #'citar-has-links
       :padding "  "
       :tag "has:links"))

    (setq citar-indicator-notes-icons
      (citar-indicator-create
       :symbol (nerd-icons-codicon
                "nf-cod-note"
                :face 'nerd-icons-blue
                :v-adjust -0.3)
       :function #'citar-has-notes
       :padding "    "
       :tag "has:notes"))

    (setq citar-indicator-cited-icons
      (citar-indicator-create
       :symbol (nerd-icons-faicon
                "nf-fa-circle_o"
                :face 'nerd-icon-green)
       :function #'citar-is-cited
       :padding "  "
       :tag "is:cited"))

(setq citar-indicators
  (list citar-indicator-files-icons
        citar-indicator-links-icons
        citar-indicator-notes-icons
        citar-indicator-cited-icons)))

Scholarly Writing Environment with Org-mode

I like to keep formatting simple. Let's use a package or two to set a decent document class:

(add-to-list 'org-latex-classes
    '("student-apa7"
      "\\documentclass[stu]{apa7}
\\hypersetup{hidelinks}
\\usepackage{times}
[NO-DEFAULT-PACKAGES]
[NO-PACKAGES]"
     ("\\section{%s}" . "\\section*{%s}")
     ("\\subsection{%s}" . "\\subsection*{%s}")
     ("\\subsubsection{%s}" . "\\subsubsection*{%s}")
     ("\\paragraph{%s}" . "\\paragraph*{%s}")
     ("\\subparagraph{%s}" . "\\subparagraph*{%s}")))

(add-to-list 'org-latex-classes
    '("student-turabian"
      "\\documentclass{turabian-researchpaper}
[NO-DEFAULT-PACKAGES]
[NO-PACKAGES]"
     ("\\section{%s}" . "\\section*{%s}")
     ("\\subsection{%s}" . "\\subsection*{%s}")
     ("\\subsubsection{%s}" . "\\subsubsection*{%s}")
     ("\\paragraph{%s}" . "\\paragraph*{%s}")
     ("\\subparagraph{%s}" . "\\subparagraph*{%s}")
     ("\\usepackage{biblatex-chicago}")))

(add-to-list 'org-latex-classes
    '("student-mla"
      "\\documentclass[stu]{mla}
\\hypersetup{hidelinks}
\\usepackage{times} "
     ("\\section{%s}" . "\\section*{%s}")
     ("\\subsection{%s}" . "\\subsection*{%s}")
     ("\\subsubsection{%s}" . "\\subsubsection*{%s}")
     ("\\paragraph{%s}" . "\\paragraph*{%s}")
     ("\\subparagraph{%s}" . "\\subparagraph*{%s}")))

       ;; org-latex-compilers = ("pdflatex" "xelatex" "lualatex"), which are the possible values for %latex

Engraving Faces

Ever wonder why code export sucks with \LaTeX ? Me neither! Let's fix it!

(use-package! engrave-faces)
(setq org-latex-listings 'engraved)

Zettelkasten environment with org-roam

Org-roam enables features essential to a Zettelkasten such as inter-ID linking.

    (use-package! org-roam
      :after md-roam
      :init (setq org-roam-directory "~/org/"))      :custom
(after! org-roam
  :ensure t
  :custom
  (setq org-roam-capture-templates
       `(
         ("d" "default" plain "%?"
          :target (file+head "%<%Y%m%d-%H%M%S>.org"
                             "#+TITLE: ${title}\n#+HTML_HEAD: <link rel=\"stylesheet\" type=\"text/css\" href=\"css/retro.css\" />\n")
          :unnarrowed t)

        ("s" "school" plain "%?"
          :target (file+head "%<%Y%m%d-%H%M%S>.org"
"#+TITLE: ${title}
,#+LATEX_CLASS: student-apa7
,#+LATEX_OPTIONS: stu,hidelinks
,#+LATEX_HEADER: \\course{}
,#+LATEX_HEADER:\\authorsnames{Judah Sotomayor}
,#+LATEX_HEADER: \\authorsaffiliations{}
,#+LATEX_HEADER: \\professor{}
,#+LATEX_HEADER: \\usepackage{times}
,#+LATEX_HEADER: \\duedate{}
,#+OPTIONS: toc:nil\n")
          :unnarrowed t)

         ("c" "encrypted" plain "%?"
          :target (file+head "%<%Y%m%d-%H%M%S>.sec.org.age"
                             "#+TITLE: ${title}\n#+FILETAGS: :secure:noexport:\n#+HTML_HEAD: <link rel=\"stylesheet\" type=\"text/css\" href=\"css/retro.css\" />\n\n\n* No Export Below This Line")
          :unnarrowed t))))

Keybinds

Org-roam has many commands, of which I have bound the most important below. This entails creating a local leader. I use r for this purpose. It is close and goes well with roam.

(after! org-roam (map! :leader (:prefix ("r" . "roam")

                :desc "Search for a node in org-roam files"
                "f" #'org-roam-node-find

                :desc "Insert the link to a node from org-roam"
                "i" #'org-roam-node-insert

                :desc "Rescan org-roam files and add new nodes to database"
                "s" #'org-roam-db-sync

                :desc "Jump to a random node"
                "r" #'org-roam-node-random

                :desc "Capture inside an existing or new node"
                "c" #'org-roam-capture

                :desc "Go to or create a daily note"
                "d" #'org-roam-dailies-goto-today

                :desc "Seek a daily note"
                "D" #'org-roam-dailies-goto-date

                :desc "Extract a subtree to a new file"
                "e" #'org-roam-extract-subtree))

            (map!
                :desc "Alternative keybind to insert a roam link while in insert mode"
                :i "M-[" #'org-roam-node-insert))

Nice UI to access Zettelkasten notes with 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 t))

(after! org-roam-ui (map! :leader (:prefix ("r" . "roam") (:prefix ("u" . "roam-ui")

                :desc "Focus the current node in org-roam-ui view"
                "f" #'org-roam-ui-node-zoom

                :desc "Focus the current node's local graph in org-roam-ui view"
                "l" #'org-roam-ui-node-local

                :desc "Begin org-roam ui mode"
                "u" #'open-org-roam-ui

                ))))
Function to pull up org-roam ui
(defun open-org-roam-ui ()
  (interactive)
  (org-roam-ui-mode)
  (async-shell-command "surf http://localhost:35901/"))

Default Browser for Export

(setq browse-url-browser-function 'browse-url-generic
      browse-url-generic-program "surf")

 '(org-file-apps
    (quote
      ((auto-mode . emacs)
      ("\\.mm\\'" . default)
      ("\\.x?html?\\'" . "surf %s")
      ("\\.pdf\\'" . default))))

Journal Environment with org-roam

(after! org-roam
(setq org-roam-dailies-capture-templates
  `(("d" "default" entry
     "* %?"
     :target (file+head "%<%Y-%m-%d>.sec.org.age"
                        "#+title: %<%Y-%m-%d>\n")))))

Property getters and setters

These are to fulfill my need to get property values for generating my journal index.

(require 'cl-lib)

(defun org-global-props-key-re (key)
  "Construct a regular expression matching key and an optional plus and eating the spaces behind.
Test for existence of the plus: (match-beginning 1)"
  (concat "^" (regexp-quote key) "\\(\\+\\)?[[:space:]]+"))

(defun org-global-props (&optional buffer)
  "Get the plists of global org properties of current buffer."
  (with-current-buffer (or buffer (current-buffer))
    (org-element-map (org-element-parse-buffer) 'keyword (lambda (el) (when (string-equal (org-element-property :key el) "PROPERTY") (nth 1 el))))))

(defun org-global-prop-value (key)
  "Get global org property KEY of current buffer.
Adding up values for one key is supported."
  (let ((key-re (org-global-props-key-re key))
    (props (org-global-props))
    ret)
    (cl-loop with val for prop in props
         when (string-match key-re (setq val (plist-get prop :value))) do
         (setq
          val (substring val (match-end 0))
          ret (if (match-beginning 1)
              (concat ret " " val)
            val)))
    ret))

Resume setup for a stellar CV

ox-extra for ":ignore:" tags

I want to be able to ignore headings on export.

(after! org
  (use-package! ox-extra
    :config
    (ox-extras-activate '(latex-header-blocks ignore-headlines))))

Resume template

(add-to-list 'org-latex-classes
             '("altacv" "\\documentclass[10pt,a4paper,ragged2e,withhyper]{altacv}
\\usepackage[rm]{roboto}
\\usepackage[defaultsans]{lato}
\\usepackage{paracol}
[NO-DEFAULT-PACKAGES]
[NO-PACKAGES]
% Change the page layout if you need to
\\geometry{left=1.25cm,right=1.25cm,top=1.5cm,bottom=1.5cm,columnsep=1.2cm}

% Use roboto and lato for fonts
\\renewcommand{\\familydefault}{\\sfdefault}

% Change the colours if you want to
\\definecolor{SlateGrey}{HTML}{2E2E2E}
\\definecolor{LightGrey}{HTML}{666666}
\\definecolor{DarkPastelRed}{HTML}{450808}
\\definecolor{PastelRed}{HTML}{8F0D0D}
\\definecolor{GoldenEarth}{HTML}{E7D192}

\\colorlet{name}{black}
\\colorlet{tagline}{black}
\\colorlet{heading}{black}
\\colorlet{headingrule}{black}
\\colorlet{subheading}{black}
\\colorlet{accent}{black}
\\colorlet{emphasis}{SlateGrey}
\\colorlet{body}{LightGrey}

% Change some fonts, if necessary
\\renewcommand{\\namefont}{\\Huge\\rmfamily\\bfseries}
\\renewcommand{\\personalinfofont}{\\footnotesize}
\\renewcommand{\\cvsectionfont}{\\LARGE\\rmfamily\\bfseries}
\\renewcommand{\\cvsubsectionfont}{\\large\\bfseries}

% Change the bullets for itemize and rating marker
% for \cvskill if you want to
\\renewcommand{\\itemmarker}{{\\small\\textbullet}}
\\renewcommand{\\ratingmarker}{\\faCircle}
"

               ("\\cvsection{%s}" . "\\cvsection*{%s}")
               ("\\cvevent{%s}" . "\\cvevent*{%s}")))

McDowell Resume Template

This template is supposed to be the standard.

(add-to-list 'org-latex-classes
             '("mcdowellcv"
               "\\documentclass[]{mcdowellcv}
                \\usepackage{amsmath}
                \\usepackage[]{multicol}
    [NO-DEFAULT-PACKAGES]
    [NO-PACKAGES]"
               ("\\section{%s}" . "\\section*{%s}")
               ("\\subsection{%s}" . "\\subsection*{%s}")
               ("\\subsubsection{%s}" . "\\subsubsection*{%s}")
               ("\\paragraph{%s}" . "\\paragraph*{%s}")
               ("\\subparagraph{%s}" . "\\subparagraph*{%s}")
               ("\\cvsection{%s}" . "\\cvsection*{%s}")
               ("\\cvevent{%s}" . "\\cvevent*{%s}")))

Better EViL keybinds

Remapping g-j/k

(map! :n "g j" #'evil-next-visual-line)
(map! :n "g k" #'evil-previous-visual-line)

Company-mode for great autocompletes

I don't really want company-mode to run on timeouts. I want VIM-like autocompletion, where C-x o and friends gives me my autocompletion.

(after! company-mode
  (setq company-idle-delay nil))
(setq company-idle-delay nil)

Initializing shell environment variables

(use-package! exec-path-from-shell)
(after! exec-path-from-shell
  (dolist (var '("SSH_AUTH_SOCK" "SSH_AGENT_PID" "GPG_AGENT_INFO"))
  (add-to-list 'exec-path-from-shell-variables var))
  (exec-path-from-shell-initialize)
  )

Md-roam

;; file-truename is optional; it seems required when you use symbolic
;; links, which Org-roam does not resolve
(use-package! md-roam
  :config
  (setq org-roam-file-extensions '("org" "md")) ; enable Org-roam for a markdown extension
  (setq md-roam-file-extension "md") ; default "md". Specify an extension such as "markdown"
  (setq md-roam-file-extension-single "md")
  (setq md-roam-use-org-extract-ref nil)

  (org-roam-db-autosync-mode 1))

COMMENT Capture template for documentation

(add-to-list 'org-roam-capture-templates
    '("m" "Markdown" plain "" :target
        (file+head "training-resources/content/${title}.md"
"---\ntitle: ${title}\nid: %<%Y-%m-%dT%H%M%S>\ncategory: \n---\n")
    :unnarrowed t))