Files
literate-dotfiles/doom.org

118 KiB

Doom Emacs Configuration

Useful Bindings

  • align-regexp: equivalent of vim-easy-align. Very useful to align tables and stuff

General Bindings

spc : Execute command
spc < Switch to buffer
spc X org-capture
spc s s Search in buffer with swiper
spc s p Search in project
spc p p Switch project
spc p t TODOs in project
spc o f Create frame
spc o e Toggle Eshell
spc n l Store link
spc g g Magit status
spc f r Open recent file
spc b B Switch to buffer
spc b d Kill current buffer
spc b i ibuffer
spc tab . Switch to workspace
spc tab n New workspace
spc tab r Rename workspace
spc m A org-archive-subtree
spc m I org-toggle-inline-images
spc m d org-deadline
spc m e org-export-dispatch
spc m o org-set-property
spc m s org-schedule
spc m t org-todo

Org-Babel Bindings

C-c C-v p org-babel-previous-src-block
C-c C-v n org-babel-next-src-block
C-c C-v e org-babel-execute-maybe
C-c C-v o org-babel-open-src-block-result
C-c C-v v org-babel-expand-src-block
C-c C-v u org-babel-goto-src-block-head
C-c C-v g org-babel-goto-named-src-block
C-c C-v r org-babel-goto-named-result
C-c C-v b org-babel-execute-buffer
C-c C-v s org-babel-execute-subtree
C-c C-v d org-babel-demarcate-block
C-c C-v t org-babel-tangle
C-c C-v f org-babel-tangle-file
C-c C-v c org-babel-check-src-block
C-c C-v j org-babel-insert-header-arg
C-c C-v l org-babel-load-in-session
C-c C-v i org-babel-lob-ingest
C-c C-v I org-babel-view-src-block-info
C-c C-v z org-babel-switch-to-session-with-code
C-c C-v a org-babel-sha1-hash
C-c C-v h org-babel-describe-bindings
C-c C-v x org-babel-do-key-sequence-in-edit-buffer

Timers:

  • C-c C-x 0: Start Timer
  • C-c C-x .: Insert timestamp
  • C-c C-x ,: Pause Timer
  • C-c C-x _: Stop Timer

Tables:

  • S-RET: copy and increment the cell at point

Evil bindings

gv Selects the previous visual
o in visual mode go to the `Other` end of the selection
g= and g- Increase/decrement number
t followed by any char goes "till" next character (not included)
f followed by any char "find" next character (included)
yt. yank until next .

Basic Configuration

Personal Information

(setq user-full-name "Dehaeze Thomas"
      user-mail-address "dehaeze.thomas@gmail.com")

Doom Config

Fonts

(setq doom-font (font-spec :family "Hack Nerd Font Mono" :size 12 :weight 'semi-light)
      doom-variable-pitch-font (font-spec :family "Hack Nerd Font Mono")
      doom-unicode-font (font-spec :family "Hack Nerd Font Mono" :size 12)
      doom-big-font (font-spec :family "Hack Nerd Font Mono" :size 19))

Theme

;; (setq doom-theme 'leuven)
(setq doom-theme 'doom-gruvbox-light)

Line numbers

(setq display-line-numbers-type t)

Mode Line

(use-package doom-modeline
  :hook (after-init . doom-modeline-mode)
  :custom
  (doom-modeline-height 25)
  (doom-modeline-bar-width 1)
  (doom-modeline-icon t)
  (doom-modeline-major-mode-icon t)
  (doom-modeline-major-mode-color-icon t)
  (doom-modeline-buffer-file-name-style 'truncate-upto-project)
  (doom-modeline-buffer-state-icon t)
  (doom-modeline-buffer-modification-icon t)
  (doom-modeline-minor-modes nil)
  (doom-modeline-enable-word-count nil)
  (doom-modeline-buffer-encoding t)
  (doom-modeline-indent-info nil)
  (doom-modeline-checker-simple-format t)
  (doom-modeline-vcs-max-length 12)
  (doom-modeline-env-version t)
  (doom-modeline-irc-stylize 'identity)
  (doom-modeline-github-timer nil)
  (doom-modeline-gnus-timer nil))

Evil

(after! evil
  (map! :m  "-"  #'dired-jump)
  (setq evil-respect-visual-line-mode nil)
  (modify-syntax-entry ?_ "w") ;; https://emacs.stackexchange.com/questions/9583/how-to-treat-underscore-as-part-of-the-word
  )

Make horizontal movement cross lines

(setq-default evil-cross-lines t)

Which Key

(after! which-key
  (setq which-key-idle-delay 0.5
        which-key-idle-secondary-delay 0.01
        which-key-sort-order 'which-key-key-order-alpha))

Visual

Automatic line wrap.

(global-visual-line-mode nil)

Turn off auto-fill mode that add line breaks.

(auto-fill-mode -1)
(remove-hook 'text-mode-hook #'turn-on-auto-fill)
(after! org
  ;; turn off auto-fill for org-mode
  (add-hook 'org-mode-hook 'turn-off-auto-fill))
(after! auctex
  (add-hook 'latex-mode-hook 'turn-off-auto-fill))

Change default alert backend

(setq alert-default-style 'libnotify)

Spell Check

(setq ispell-dictionary "en")
(setq ispell-program-name "aspell")

Correct last work using C-..

(defun tdh-correct-last-word ()
  (interactive)
  (save-excursion
    (+spell/previous-error)
    (+spell/correct)
    )
  )

(map! :map org-mode-map
      :i "C-." #'tdh-correct-last-word)

Go to previous/next spell mistake using g[ and g]:

(map! :map evil-normal-state-map
      "g]" #'spell-fu-goto-next-error)
(map! :map evil-normal-state-map
      "g[" #'spell-fu-goto-previous-error)

C-cedilla issue

This tells GTK builds of Emacs to use native input method handling

(setq x-gtk-use-system-tooltips nil)
(setq x-gtk-use-native-input t)

Lockfiles

(setq create-lockfiles nil)

Disable highlight of current line

This helps to speed-up emacs.

(global-hl-line-mode -1)
(after! org
  (add-hook 'org-mode-hook
      (lambda()
          (hl-line-mode -1)
          (global-hl-line-mode -1))
      't
  ))

Remap jump-forward key binding

(with-eval-after-load 'better-jumper
  (map!
  :desc "Jump Forward"
  "C-i" #'better-jumper-jump-forward))

Magit

(setenv "GIT_ASKPASS" "git-gui--askpass")

;; (after! magit
;;   (setq magit-diff-refine-hunk 'all)
;;   (setq magit-repolist-columns '(("Name" 25 magit-repolist-column-ident nil)
;;                                  ("Status" 7 magit-repolist-column-flag)
;;                                  ("B<U" 3 magit-repolist-column-unpulled-from-upstream
;;                                   ((:right-align t)
;;                                    (:help-echo "Upstream changes not in branch")))
;;                                  ("B>U" 3 magit-repolist-column-unpushed-to-upstream
;;                                   ((:right-align t)
;;                                    (:help-echo "Local changes not in upstream")))
;;                                  ("Path" 99 magit-repolist-column-path nil)))
;;   )

Dired

  • C-c C-e Writable Dired mode, when changes are done C-c C-c.

This works also with C-x C-q

  • C-c C-r use rsync to copy file in the background
  • + Create a directory
  • R Rename / move
  • C Copy
  • d Delete
  • m Mark
  • U unmark all marked
  • t invert the selection
  • u unmark / undelete
  • x actually delete files/directories marked for deletion
  • ! Execute shell command on this file, or currently marked files
  • %m mark by pattern
  • o sort by time/name
  • ( Hide details
  • ) Show git infos
(after! magit
  (setq dired-listing-switches "-lAGh1v --group-directories-first")
  (add-hook 'dired-mode-hook
            (lambda ()
              (dired-hide-details-mode)
              (dired-sort-toggle-or-edit)))
  )

PDF-Tools

Function that opens current pdf page as an SVG file with Inkscape.

(defun tdh-screenshot-page ()
  "Open current page as an SVG file with Inkscape"
  (interactive)
  (if (string-match "_" (file-name-base buffer-file-name))
      (setq filename (read-string "Enter file name:" (car (split-string (file-name-base buffer-file-name) "_"))))
    (setq filename (read-string "Enter file name:")))
  (setq filepath (concat "/tmp/" filename ".svg"))
  (shell-command (concat "pdftk " buffer-file-name " cat " (number-to-string (pdf-view-current-page)) " output /tmp/pdf_page.pdf"))
  (shell-command (concat "pdf2svg /tmp/pdf_page.pdf " filepath))
  (start-process "" nil "inkscape" filepath))

(after! pdf-tools
  (map! :map pdf-view-mode-map
        (:desc "Screenshot"
         :ni "C-c s" 'tdh-screenshot-page)
        ))

Flycheck

Disable flycheck for now with orgmode buffers:

(defun disable-flycheck-mode ()
  (interactive)
  (flycheck-mode -1))
(add-hook 'org-mode-hook 'disable-flycheck-mode)

Tramp

(after! tramp
  (add-to-list 'tramp-remote-process-environment "GIT_AUTHOR_EMAIL=thomas.dehaeze@esrf.fr")
  (add-to-list 'tramp-remote-process-environment "GIT_AUTHOR_NAME='Thomas Dehaeze'")
  (add-to-list 'tramp-remote-process-environment "GIT_COMMITTER_EMAIL=thomas.dehaeze@esrf.fr")
  (add-to-list 'tramp-remote-process-environment "GIT_COMMITTER_EMAIL='Thomas Dehaeze'")
  )

Helm AG

Increase the number of "columns" when search for text:

(setq counsel-rg-base-command
      "rg --max-columns 1000 --with-filename --no-heading --line-number --color never %s")

Others

(setq auto-save-default t)

Org Mode

Org General Config

(setq org-directory "~/Cloud/org/")
(after! org
  (setq org-directory "~/Cloud/org/")

  ;; Replace the content marker, “⋯”, with a nice unicode arrow.
  (setq org-ellipsis " ⤵")

  (setq org-default-notes-file "~/Cloud/org/refile.org")

  ;; Avoid accidentally editing folded regions, say by adding text after an Org “⋯”.
  (setq org-catch-invisible-edits 'show-and-error)

  ;; The following setting hides blank lines between headings which keeps folded view nice and compact.
  (setq org-cycle-separator-lines 0)

  ;; Indent according to the outline structure
  (setq org-startup-indented t)
  (setq org-startup-folded t)

  ;; Record the information of when the task was marked as DONE
  (setq org-log-done 'time)

  ;; begining of line on heading behavior
  (setq org-special-ctrl-a/e nil)

  ;; Automatic save all org buffers after 30s of innactivity
  (add-hook 'after-save-hook 'org-save-all-org-buffers)
)

TAB was changed to toggle only the visibility state of the current subtree, rather than cycle through it recursively. This can be reversed with:

(after! evil-org
  (remove-hook 'org-tab-first-hook #'+org-cycle-only-current-subtree-h))

https://github.com/doomemacs/doomemacs/issues/6478#issuecomment-1406167570

(after! evil
  (setq org-fold-core-style 'overlays)
  (evil-select-search-module 'evil-search-module 'evil-search)
  )

Org Inline Images

Display the real size of images and not the one set with attr_latex: :width \linewidth for instance.

(after! org
  (setq org-image-actual-width t))

Org Links

(after! org
  (setq org-link-abbrev-alist
    '(("bib" . "~/Cloud/brain/biblio/references.bib::%s")
      ("notes" . "~/Cloud/brain/%s.org")
      ("papers" . "~/Cloud/pdfs/%s.pdf")))
  )
(defun tdh/pdf-link (filename)
  (start-process "" nil "zathura" (concat "~/Cloud/pdfs/" filename ".pdf"))
  "")

(after! org
  (org-link-set-parameters "pdf" :follow #'tdh/pdf-link)
  )

Org Tagging

(after! org
  ;; Align Tags and flush right
  (setq org-tags-column -78)
  ;; Tags with fast selection keys
  (setq org-tag-alist (quote (("@home" . ?h)
                              ("@work" . ?w)
                              ("@christophe" . ?c)
                              ("@veijo" . ?v))))
  )

Org Refile

(after! org
  (setq org-refile-targets '((org-agenda-files . (:maxlevel . 6))))
  )

Org TODO

(after! org
  ;; Tags with fast selection keys
  (setq org-todo-keywords '(
                            (sequence "TODO(t)" "MAIL(m)" "|" "DONE(d)")
                            (sequence "READ(r)" "|" "DONE(d)")
                            (sequence "WAIT(w@/!)" "DELE(e)" "|" "CANC(c@/!)")
                            (sequence "QUES(q)" "|" "ANSW(a)")
                            ))

  ;; Display of the keywords
  (setq org-todo-keyword-faces
        '(("TODO" . (:foreground "#cc241d" :weight bold)) ;; red
          ("MAIL" . (:foreground "#cc241d" :weight bold)) ;; red
          ("READ" . (:foreground "#cc241d" :weight bold)) ;; red
          ("ANSW" . (:foreground "#689d6a" :weight bold)) ;; aqua
          ("DONE" . (:foreground "#689d6a" :weight bold)) ;; aqua
          ("QUES" . (:foreground "#d65d0e" :weight bold)) ;; orange
          ("WAIT" . (:foreground "#d65d0e" :weight bold)) ;; orange
          ("CANC" . (:foreground "#a89984" :weight bold)) ;; grey
          ("DELE" . (:foreground "#98971a" :weight bold)))) ;; green
  )

Org Archive

https://gist.github.com/Fuco1/e86fb5e0a5bb71ceafccedb5ca22fcfb Archive subtrees under the same hierarchy as original in the archive files

(after! org
  (defadvice org-archive-subtree (around fix-hierarchy activate)
    (let* ((fix-archive-p (and (not current-prefix-arg)
                               (not (use-region-p))))
           (location (org-archive--compute-location org-archive-location))
           (afile (car location))
           (offset (if (= 0 (length (cdr location)))
                       1
                     (1+ (string-match "[^*]" (cdr location)))))
           (buffer (or (find-buffer-visiting afile) (find-file-noselect afile))))
      ad-do-it
      (when fix-archive-p
        (with-current-buffer buffer
          (goto-char (point-max))
          (while (> (org-current-level) offset) (org-up-heading-safe))
          (let* ((olpath (org-entry-get (point) "ARCHIVE_OLPATH"))
                 (path (and olpath (split-string olpath "/")))
                 (level offset)
                 tree-text)
            (when olpath
              (org-mark-subtree)
              (setq tree-text (buffer-substring (region-beginning) (region-end)))
              (let (this-command) (org-cut-subtree))
              (goto-char (point-min))
              (save-restriction
                (widen)
                (-each path
                  (lambda (heading)
                    (if (re-search-forward
                         (rx-to-string
                          `(: bol (repeat ,level "*") (1+ " ") ,heading)) nil t)
                        (org-narrow-to-subtree)
                      (goto-char (point-max))
                      (unless (looking-at "^")
                        (insert "\n"))
                      (insert (make-string level ?*)
                              " "
                              heading
                              "\n"))
                    (cl-incf level)))
                (widen)
                (org-end-of-subtree t t)
                (org-paste-subtree level tree-text))))))))
  )

Org Agenda

General configuration

(after! org
  ;; File to save todo items
  (setq org-agenda-files (list "~/Cloud/org/"))

  ;; Include archived files
  (setq org-agenda-archives-mode nil)

  ;; Set priority range from A to C with default A
  (setq org-highest-priority ?A)
  (setq org-lowest-priority  ?C)
  (setq org-default-priority ?C)

  ;; Set colours for priorities
  (setq org-priority-faces '((?A . (:foreground "#FB4934"))
                             (?B . (:foreground "#FABD2F"))
                             (?C . (:foreground "#98971A"))))

  ;; Open agenda in current window
  (setq org-agenda-window-setup 'current-window)

  ;; Set default first day of agenda
  (setq org-agenda-start-day nil)
  (setq org-agenda-start-on-weekday 1)
  (setq org-agenda-span 7)

  (setq org-agenda-prefix-format
        '((agenda  . "  %?-12t% s")
          (todo  . "") ;; Don't show the filename for reading agenda
          (tags  . " %-12:c")
          (search . " %-12:c"))
        )
  )

Org Agenda Custom Views

(after! org-agenda
  (defun tdh-org-agenda-skip-scheduled ()
    (org-agenda-skip-entry-if 'scheduled 'deadline 'regexp "\n]+>"))

  (defun tdh-org-agenda-phd-files ()
    (seq-mapcat
     (lambda (subdir)
       (directory-files subdir t "\\.org$" t))
     (seq-filter #'file-directory-p
                 (directory-files "~/Cloud/work-projects/ID31-NASS/phd-thesis-chapters" t "^[^.]" t))))

  (setq org-agenda-custom-commands
        '(("T" "test"
           ((org-ql-block '(planning)
                          ((org-ql-block-header "To refill")))
            ))
          ("p" "PhD Thesis"
           ((agenda "" ((org-agenda-span 3)
                        (org-deadline-warning-days 0)
                        (org-agenda-block-separator nil)
                        (org-agenda-format-date "%A %-e %B %Y")
                        (org-agenda-skip-function '(org-agenda-skip-entry-if 'todo 'done))
                        (org-agenda-overriding-header "Next:")))
            (org-ql-block '(and (not (tags "@home"))
                                (not (tags "@biblio"))
                                (todo "TODO")
                                (priority "A"))
                          ((org-ql-block-header "Important:")))
            (org-ql-block '(and (not (tags "@home"))
                                (todo "DELE"))
                          ((org-ql-block-header "Delegated:")))
            (org-ql-block '(and (not (tags "@home"))
                                (todo "WAIT"))
                          ((org-ql-block-header "On hold:")))
            )
           ((org-agenda-files (tdh-org-agenda-phd-files))))

          ("w" "Work"
           ((agenda "" ((org-agenda-span 3)
                        (org-deadline-warning-days 0)
                        (org-agenda-block-separator nil)
                        (org-agenda-format-date "%A %-e %B %Y")
                        (org-agenda-skip-function '(org-agenda-skip-entry-if 'todo 'done))
                        (org-agenda-overriding-header "Next:")))
            (org-ql-block '(and (not (tags "@home"))
                                (not (tags "@biblio"))
                                (todo "TODO")
                                (priority "A"))
                          ((org-ql-block-header "Important:")))
            (org-ql-block '(and (not (tags "@home"))
                                (todo "DELE"))
                          ((org-ql-block-header "Delegated:")))
            (org-ql-block '(and (not (tags "@home"))
                                (todo "WAIT"))
                          ((org-ql-block-header "On hold:")))
            (org-ql-block '(and (tags "inbox"))
                          ((org-ql-block-header "To refill:")))
            ))
          ("h" "Home"
           ((org-ql-block '(and (tags "@home")
                                (todo "TODO")
                                (priority "A"))
                          ((org-ql-block-header "Things to do")))
            (org-ql-block '(and (tags "@home")
                                (todo "TODO")
                                (priority "B"))
                          ((org-ql-block-header "Things to do")))
            (org-ql-block '(and (tags "@home")
                                (todo "TODO")
                                (priority "C"))
                          ((org-ql-block-header "Things to do")))))
          ("q" "Questions to ask"
           ((org-ql-block '(and (todo "QUES")
                                (tags "@christophe"))
                          ((org-ql-block-header "Questions to Christophe")))
            (org-ql-block '(and (todo "QUES")
                                (tags "@veijo"))
                          ((org-ql-block-header "Questions to Veijo")))
            (org-ql-block '(and (todo "QUES")
                                (not (tags "@veijo" "@christophe")))
                          ((org-ql-block-header "Other Questions")))))
          ("R" "Already read Articles and Books"
           ((org-ql-block '(and (todo "DONE")
                                (level 1)
                                (tags "article" "inproceedings" "techreport" "inbook"))
                          ((org-ql-block-header "Articles")))
            (org-ql-block '(and (todo "DONE")
                                (level 1)
                                (tags "book"))
                          ((org-ql-block-header "Books")))
            (org-ql-block '(and (todo "DONE")
                                (level 1)
                                (tags "phdthesis"))
                          ((org-ql-block-header "Phd Thesis")))
            (org-ql-block '(and (todo "DONE")
                                (level 1)
                                (not (tags "article" "inproceedings" "techreport" "inbook" "book" "phdthesis")))
                          ((org-ql-block-header "Other Things"))))
           ((org-agenda-files '("~/Cloud/brain/"))))
          ("r" "Articles and Books to read"
           ((org-ql-block '(and (todo "READ")
                                (level 1)
                                (tags "article" "inproceedings" "techreport" "inbook"))
                          ((org-ql-block-header "Article to Read")))
            (org-ql-block '(and (todo "READ")
                                (level 1)
                                (tags "book"))
                          ((org-ql-block-header "Books to Read")))
            (org-ql-block '(and (todo "READ")
                                (level 1)
                                (tags "phdthesis"))
                          ((org-ql-block-header "Phd Thesis to Read")))
            (org-ql-block '(and (todo "READ")
                                (level 1)
                                (not (tags "article" "inproceedings" "techreport" "inbook" "book" "phdthesis")))
                          ((org-ql-block-header "Other Things to Read"))))
           ((org-agenda-files '("~/Cloud/brain/")))))
        )
  )

Org Structure Template

(after! org
  (require 'org-tempo)
  (setq org-structure-template-alist
    '(("c" . "center")
      ("C" . "comment")
      ("mm" . "src matlab")
      ("mf" . "src matlab :exports none")
      ("mv" . "src matlab :results value replace :exports results :tangle no")
      ("l" . "src emacs-lisp")
      ("q" . "quote")
      ("s" . "src")
      ("ba" . "answer")
      ("bd" . "definition")
      ("be" . "exampl")
      ("bx" . "exercice")
      ("bq" . "question")
      ("bs" . "summary")
      ("bS" . "seealso")
      ("bh" . "hint")
      ("bn" . "note")
      ("bi" . "important")
      ("bc" . "caution")
      ("bw" . "warning")
      ))
)

Org Capture

Documentation:

(after! org
  (setq org-capture-templates
        (quote (("t"    ; key
                 "Todo" ; name
                 entry  ; type
                 (file+headline "~/Cloud/org/work-tasks.org" "Inbox") ; target
                 "** TODO %?\n%U\n" ; template
                 )
                ("M"    ; key
                 "Meeting" ; name
                 entry  ; type
                 (file+headline "~/Cloud/org/work-tasks.org" "Meetings") ; target
                 "** %?\n%(org-insert-time-stamp (org-read-date nil t \"+0d\"))\n" ; template
                 )
                ("m"    ; key
                 "Mail" ; name
                 entry  ; type
                 (file+headline "~/Cloud/org/work-tasks.org" "Mails") ; target
                 "** TODO [#A] %?\nSCHEDULED: %(org-insert-time-stamp (org-read-date nil t \"+0d\"))\n%a\n" ; template
                 )
                ("r"    ; key
                 "Reference" ; name
                 entry  ; type
                 (file+headline "~/Cloud/org/inbox-ereader.org" "Things to Read") ; target
                 "** TODO [#B] %?\n" ; template
                 )
                ("pm"
                 "Org-Protocol Mail"
                 entry
                 (file+headline "~/Cloud/org/work-tasks.org" "Mails")
                 "* TODO [#C] %:description [[message:%:link][link]]\nSCHEDULED: %(org-insert-time-stamp (org-read-date nil t \"+0d\"))\n%i\n"
                 :immediate-finish t
                 )
                ("ps"
                 "Org-Protocol Sent Mail"
                 entry
                 (file+headline "~/Cloud/org/work-tasks.org" "Mails")
                 "* WAIT %:description [[message:%:link][link]]\n%(org-insert-time-stamp (org-read-date nil t \"+0d\"))\n- to: %i\n\n\n\n"
                 :immediate-finish t
                 )
                ("pu"
                 "Org-Protocol Url"
                 entry
                 (file+headline "~/Cloud/org/work-tasks.org" "Inbox")
                 "* [[%:link][%:description]]\nCaptured On: %U\n\n"
                 :immediate-finish t
                 )
                ("pt"
                 "Org-Protocol text"
                 entry
                 (file+headline "~/Cloud/org/work-tasks.org" "Inbox")
                 "* %:description\nSource: %:link\nCaptured On: %U\n\n#+begin_quote\n%i\n#+end_quote\n\n"
                 :immediate-finish t
                 )
                )))
  )

Org Export

Basic configuration:

(after! org
  ;; How many levels of headline to export
  (setq org-export-headline-levels 4)

  ;; Authorize BIND to set local variables
  (setq org-export-allow-bind-keywords t)

  ;; Use doc instead of odt
  (setq org-odt-preferred-output-format "doc")

  ;; Search collapse items
  (setq search-invisible t)
  )

Some defaults:

(after! org
  (setq org-export-with-author t)
  (setq org-export-with-creator nil)
  (setq org-export-with-date t)
  (setq org-export-with-toc t)
  (setq org-export-with-drawers nil)
  (setq org-export-with-sub-superscripts nil)
  (setq org-export-with-todo-keywords nil)
  )

Do not export headline with the :ignore: tag:

;; Used to not export headings with :ignore: tag
(after! org
  (require 'ox-extra)
  (ox-extras-activate '(ignore-headlines)))

Org-ql

(use-package! org-ql
  :after org)

Org Effort

(after! org
  (setq org-global-properties
        '(("Effort_ALL". "0 0:10 0:30 1:00 2:00 3:00 4:00")))
  )

Open Files

(after! org
  (setq org-file-apps
        '((auto-mode . emacs)
          ("\\.x?html?\\'" . "firefox %s")
          ("\\.pdf\\'" . "zathura \"%s\"")
          ("\\.pdf::\\([0-9]+\\)\\'" . "zathura \"%s\" -p %1")))
  )

HTML Export

HTML Defaults

(after! org
  (setq org-html-head "<meta name=\"viewport\" content=\"width=device-width,initial-scale=1.0\">")
  (setq org-html-head-extra "")

  (setq org-html-head-include-default-style nil)
  (setq org-html-head-include-scripts nil)

  (setq org-html-viewport nil)

  (setq org-html-html5-fancy t)
  (setq org-html-doctype "xhtml-strict")

  (setq org-html-wrap-src-lines nil)

  ;; Export with css class instead of inline css
  (setq org-html-htmlize-output-type 'css)
  )

Footnotes

(after! org
  (setq org-html-footnotes-section
        "<div id=\"footnotes\">\n<h2 class=\"footnotes\">%s</h2>\n<div id=\"text-footnotes\">\n%s\n</div>\n</div>"))

MathJax

(after! org
  (setq org-html-mathjax-template
        "<script>
            MathJax = {
            svg: {
             scale: 1,
             fontCache: \"global\"
            },
            tex: {
              tags: \"ams\",
              multlineWidth: \"85%\",
              tagSide: \"right\",
              tagIndent: \".8em\",
              macros: {bm: [\"\\\\boldsymbol{#1}\",1]}
            }
            };
          </script>
          <script id=\"MathJax-script\" async src=\"%PATH\"></script>")

  (setq org-html-mathjax-options
        '((path "https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-svg.js" )
          (scale "1")
          (autonumber "ams")
          (tagindent ".8em")
          (tagside "right")))
  )

MP4 Video - video link

(defun org-video-link-export (path desc backend)
  (let ((ext (file-name-extension path)))
    (cond
     ((eq 'html backend)
      (format "<video preload='metadata' controls='controls'><source type='video/%s' src='%s' /></video>" ext path))
     ;; fall-through case for everything else
     (t
      path))))

(after! org
  (org-link-set-parameters "video" :export 'org-video-link-export)

  (org-export-string-as "video:xxx.mp4" 'html t)
  )

Org Xournalpp

(use-package! org-xournalpp
  :config
  (add-hook 'org-mode-hook 'org-xournalpp-mode))

Org LaTeX

LaTeX Fragments

(after! org
  ;; Highligh latex parts in org mode
  (setq org-highlight-latex-and-related '(latex script entities))

  ;; Use F9 to globally generate all the latex fragments
  (map! :map org-mode-map
        :n "<f9>"
        (lambda () (interactive) (org-preview-latex-fragment 16)))

  ;; Put all the preview images in some directory
  (setq org-preview-latex-image-directory "~/.local/share/ltximg/")

  ;; Define backends to preview LaTeX fragments
  (setq org-preview-latex-process-alist '((imagemagick
                                           :programs ("pdflatex" "convert")
                                           :description "pdf > png"
                                           :message "you need to install the programs: pdflatex and imagemagick."
                                           :image-input-type "pdf"
                                           :image-output-type "png"
                                           :image-size-adjust (1.0 . 1.0)
                                           :latex-compiler ("pdflatex -interaction nonstopmode -output-directory %o %f")
                                           :image-converter ("convert -density 100 -trim -antialias %f -quality 100 %O"))
                                          (dvipng
                                           :programs ("latex" "dvipng")
                                           :description "dvi > png"
                                           :message "you need to install the programs: latex and dvipng."
                                           :image-input-type "dvi"
                                           :image-output-type "png"
                                           :image-size-adjust (0.4 . 0.4)
                                           :latex-compiler ("latex -interaction nonstopmode -output-directory %o %f")
                                           :image-converter ("dvipng -D %D -T tight -o %O %f"))
                                          (pdf2svg
                                           :programs ("pdflatex" "pdftocairo" "pdfcrop")
                                           :description "pdf > png"
                                           :message "you need to install the programs: pdflatex, pdftocairo and pdfcrop."
                                           :image-input-type "pdf"
                                           :image-output-type "svg"
                                           :image-size-adjust (1.0 . 1.0)
                                           :latex-compiler ("pdflatex -interaction nonstopmode -output-directory %o %f")
                                           :image-converter ("pdfcrop %f %f && pdf2svg %f %O"))
                                          (pdf2dvi
                                           :programs ("pdflatex" "dvipng")
                                           :description "pdf > png"
                                           :message "you need to install the programs: pdflatex, pdftocairo and pdfcrop."
                                           :image-input-type "dvi"
                                           :image-output-type "png"
                                           :image-size-adjust (0.4 . 0.4)
                                           :latex-compiler ("pdflatex -output-format dvi -interaction nonstopmode -output-directory %o %f")
                                           :image-converter ("dvipng -D %D -T tight -o %O %f"))
                                          (dvisvgm
                                           :programs ("latex" "dvisvgm")
                                           :description "xdi > svg"
                                           :message "you need to install the programs: xetex and dvisvgm."
                                           :image-input-type "dvi"
                                           :image-output-type "svg"
                                           :image-size-adjust (0.6 . 0.6)
                                           :latex-compiler ("latex -interaction nonstopmode -output-directory %o %f")
                                           :image-converter ("dvisvgm %f --no-fonts --exact-bbox --scale=%S --output=%O"))
                                          ))

  ;; Use imagemagick/dvisvgm to generate png from pdf
  (setq org-preview-latex-default-process 'dvisvgm)

  ;; Don't change the font size for subscripts and superscripts in latex fragments.
  ;; This cause the orgmode tables not to be well aligned.
  (setq font-latex-fontify-script nil)

  ;; Colors of latex fragments
  (plist-put org-format-latex-options :foreground nil)
  (plist-put org-format-latex-options :background nil)
  ;; (setq org-format-latex-options (plist-put org-format-latex-options :foreground 'default))
  ;; (setq org-format-latex-options (plist-put org-format-latex-options :background 'default))
  )

From https://karthinks.com/software/scaling-latex-previews-in-emacs/, scale the LaTeX fragments with the text:

(after! org
  (defun my/text-scale-adjust-latex-previews ()
    "Adjust the size of latex preview fragments when changing the
buffer's text scale."
    (pcase major-mode
      ('latex-mode
       (dolist (ov (overlays-in (point-min) (point-max)))
         (if (eq (overlay-get ov 'category)
                 'preview-overlay)
             (my/text-scale--resize-fragment ov))))
      ('org-mode
       (dolist (ov (overlays-in (point-min) (point-max)))
         (if (eq (overlay-get ov 'org-overlay-type)
                 'org-latex-overlay)
             (my/text-scale--resize-fragment ov))))))

  (defun my/text-scale--resize-fragment (ov)
    (overlay-put
     ov 'display
     (cons 'image
           (plist-put
            (cdr (overlay-get ov 'display))
            :scale (+ 1.0 (* 0.25 text-scale-mode-amount))))))

  (add-hook 'text-scale-mode-hook #'my/text-scale-adjust-latex-previews)
  )

LaTeX Classes

(after! org
;; Custom classes to use when exporting to latex
(add-to-list 'org-latex-classes
          '("beamer"
            ,(concat "\\documentclass[presentation]{beamer}\n"
                     "[DEFAULT-PACKAGES]"
                     "[PACKAGES]"
                     "[EXTRA]\n")
            ("\\section{%s}" . "\\section*{%s}")
            ("\\subsection{%s}" . "\\subsection*{%s}")
            ("\\subsubsection{%s}" . "\\subsubsection*{%s}")))
(add-to-list 'org-latex-classes
             '("clean-cheatsheet"
               "\\documentclass{clean-cheatsheet}"
               ("\\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
             '("clean-beamer"
               "\\documentclass{clean-beamer}"
               ("\\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
             '("cleanreport"
               "\\documentclass{cleanreport}"
               ("\\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
             '("scrartcl"
               "\\documentclass{scrartcl}"
               ("\\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
             '("scrreprt"
               "\\documentclass[a4paper, 10pt, DIV=12, parskip=full]{scrreprt}"
               ("\\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
             '("biblioreport"
               "\\documentclass{biblioreport}"
               ("\\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
             '("moderncv"
               "\\documentclass{moderncv}"
               ("\\section{%s}" . "\\section*{%s}")
               ("\\subsection{%s}" . "\\subsection*{%s}")
               ("\\subsubsection{%s}" . "\\subsubsection*{%s}")
               ("\\paragraph{%s}" . "\\paragraph*{%s}")
               ("\\subparagraph{%s}" . "\\subparagraph*{%s}"))
             )

)

Ox Latex Subfigure package

(use-package! ox-latex-subfigure
  :load-path "~/.config/doom/packages/ox-latex-subfigure/"
  :config (require 'ox-latex-subfigure))

Clear page before heading

https://emacs.stackexchange.com/questions/30575/adding-latex-newpage-before-a-heading/30892

(after! org
  (defun tdh-get-headline-string-element  (headline backend info)
    (let ((prop-point (next-property-change 0 headline)))
      (if prop-point (plist-get (text-properties-at prop-point headline) :parent))))

  (defun tdh-ensure-latex-clearpage (headline backend info)
    (when (org-export-derived-backend-p backend 'latex)
      (let ((elmnt (tdh-get-headline-string-element headline backend info)))
        (when (and elmnt (org-element-property :CLEARPAGE elmnt))
          (concat "\\clearpage\n" headline)))))

  (add-to-list 'org-export-filter-headline-functions
               'tdh-ensure-latex-clearpage)
  )

TODO Default added packages

(after! org
  (setq org-latex-default-packages-alist
        '(("AUTO" "inputenc" t ("pdflatex")) ;; for basic font and character selection
          ("T1" "fontenc" t ("pdflatex")) ;; for basic font and character selection
          ("" "graphicx" t) ;; for including images
          ("" "grffile" t) ;; allow periods and spaces in graphics file names
          ("" "longtable" nil) ;; For multipage tables
          ("" "wrapfig" nil) ;; for figure placement
          ("" "rotating" nil) ;; for sideways figures and tables
          ("normalem" "ulem" t) ;; for underline and strike-through
          ("" "amsmath" t) ;; for subscript and superscript and math environments
          ("" "textcomp" t) ;; for various symbols
          ("" "amssymb" t) ;; for various symbols
          ("" "capt-of" nil) ;; for captions outside of floats
          ("" "hyperref" nil)) ;; for cross references
        )
  )
(after! org
  (add-to-list 'org-latex-packages-alist '("" "siunitx" t))
  (add-to-list 'org-latex-packages-alist '("" "array" t))
  (add-to-list 'org-latex-packages-alist '("" "tabularx" t))
  (add-to-list 'org-latex-packages-alist '("" "booktabs" t))
  (add-to-list 'org-latex-packages-alist '("" "bm" t))
  (add-to-list 'org-latex-packages-alist '("most" "tcolorbox" t))
  )

Some configurations

(after! org
  ;; Setup default option for image size when exporting to LaTeX
  (setq org-latex-image-default-scale "")
  (setq org-latex-image-default-width "")
  (setq org-latex-image-default-height "")
  (setq org-latex-image-default-option "scale=1")

  ;; Use define labels instead of automatic generated ones
  (setq org-latex-prefer-user-labels t)

  ;; Captions above the table
  (setq org-latex-caption-above '(table))

  ;; Settings to export code with `minted' instead of `verbatim'.
  (setq org-latex-listings 'minted)

  ;; Set the following as images
  (setq org-latex-inline-image-rules '(("file" . "\\.\\(pdf\\|jpeg\\|jpg\\|png\\|ps\\|eps\\|tikz\\|pgf\\|svg\\|gif\\)\\'")))

  ;; Command used when exporting to pdf
  (setq org-latex-pdf-process
        '("latexmk -cd -pdflatex=\"pdflatex -synctex=1 -shell-escape -interaction nonstopmode -output-directory %o\" -pdf -f %f"))

  ;; ;; Better display of timestamps
  ;; (setq org-latex-diary-timestamp-format "\\footnotesize{\\textit{%s}}"
  ;;       org-latex-inactive-timestamp-format "\\footnotesize{\\textit{%s}}"
  ;;       org-latex-active-timestamp-format "\\footnotesize{\\textit{%s}}")

  (defun org-export-filter-timestamp-remove-brackets (timestamp backend info)
    "removes relevant brackets from a timestamp"
    (cond
     ((org-export-derived-backend-p backend 'latex)
      (replace-regexp-in-string "[<>]\\|[][]" "" timestamp))
     ((org-export-derived-backend-p backend 'html)
      (replace-regexp-in-string "&[lg]t;\\|[][]" "" timestamp))))
  
  (eval-after-load 'ox '(add-to-list
                         'org-export-filter-timestamp-functions
                         'org-export-filter-timestamp-remove-brackets))
  
  )

Beamer

Bold Text

(after! org
  (defun tdh-my-beamer-bold (contents backend info)
    (when (eq backend 'beamer)
      (replace-regexp-in-string
       (concat "\\`\\\\" "[A-Za-z0-9]+") ;; If not, orgmode is crazy...
       "\\\\textbf"
       contents)))

  (add-to-list 'org-export-filter-bold-functions 'tdh-my-beamer-bold)
  )

Special Environments

  • Make some comment those special environments
(after! org-beamer
  (add-to-list 'org-beamer-environments-extra
               '("cbox" ;; Name of environment
                 "m" ;; Selection key
                 "\\onslide%a{\\begin{cbox}[%h]%O"
                 "\\end{cbox}}\\vspace{0.5em}"))
  (add-to-list 'org-beamer-environments-extra
               '("csubbox" ;; Name of environment
                 "M" ;; Selection key
                 "\\onslide%a{\\tcbsubtitle{%h}"
                 "}"))
  )

Number Equations

https://kitchingroup.cheme.cmu.edu/blog/2016/11/07/Better-equation-numbering-in-LaTeX-fragments-in-org-mode/

(after! org
  (defun tdh-org-renumber-environment (orig-func &rest args)
    "A function to inject numbers in LaTeX fragment previews."
    (let ((results '())
          (counter -1)
          (numberp))

      (setq results (loop for (begin .  env) in
                          (org-element-map (org-element-parse-buffer) 'latex-environment
                            (lambda (env)
                              (cons
                               (org-element-property :begin env)
                               (org-element-property :value env))))
                          collect
                          (cond
                           ((and (string-match "\\\\begin{equation}" env)
                                 (not (string-match "\\\\tag{" env)))
                            (incf counter)
                            (cons begin counter))
                           ((string-match "\\\\begin{align}" env)
                            (prog2
                                (incf counter)
                                (cons begin counter)
                              (with-temp-buffer
                                (insert env)
                                (goto-char (point-min))
                                ;; \\ is used for a new line. Each one leads to a number
                                (incf counter (count-matches "\\\\$"))
                                ;; unless there are nonumbers.
                                (goto-char (point-min))
                                (decf counter (count-matches "\\nonumber")))))
                           (t
                            (cons begin nil)))))

      (when (setq numberp (cdr (assoc (point) results)))
        (setf (car args)
              (concat
               (format "\\setcounter{equation}{%s}\n" numberp)
               (car args)))))

    (apply orig-func args))

  (advice-add 'org-create-formula-image :around #'tdh-org-renumber-environment)
  )

LaTeX macro both for LaTeX and HTML export

https://www.reddit.com/r/orgmode/comments/7u2n0h/tip_for_defining_latex_macros_for_use_in_both/

(after! org
  (add-to-list 'org-src-lang-modes '("latex-macros" . latex))

  (defvar org-babel-default-header-args:latex-macros
    '((:results . "raw")
      (:exports . "results")))

  (defun prefix-all-lines (pre body)
    (with-temp-buffer
      (insert body)
      (string-insert-rectangle (point-min) (point-max) pre)
      (buffer-string)))

  (defun org-babel-execute:latex-macros (body _params)
    (concat
     "\n#+begin_export html\n<div style=\"display: none\"> \\(\n"
     body
     "\n\\)</div>\n#+end_export\n"))
  )

Automatically run startblock when opening org-mode files

(after! org
  (defun tdh-eval-startblock ()
    (if (member "startblock" (org-babel-src-block-names))
        (save-excursion
          (org-babel-goto-named-src-block "startblock")
          (org-babel-execute-src-block))
      nil
      )
    )

  (add-hook 'org-mode-hook 'tdh-eval-startblock)
  )

Org mode and Yasnippet

TAB used not to work well with Yasnippet (github issue), with the following, it works well:

(map! :map org-mode-map :after yasnippet ;; Retain org-mode's native TAB functionality but allow yas-expand when a snippet is available
      :nvi [tab]        yas-maybe-expand ;; Optionally, bind other keys for snippet navigation
      :nvi "C-c n"      #'yas-next-field
      :nvi "C-c p"      #'yas-prev-field)

Some function

(defun org-syntax-convert-case-to-lower ()
  "Convert all #+KEYWORDS to #+keywords."
  (interactive)
  (save-excursion
    (goto-char (point-min))
    (let ((count 0)
          (case-fold-search nil))
      (while (re-search-forward "#\\+[A-Z_]+" nil t)
        (replace-match (downcase (match-string 0)) t)
        (setq count (1+ count)))
      (message "Replaced %d occurances" count))))

Render Tables

https://www.reddit.com/r/emacs/comments/d3a8or/pretty_org_tables_in_the_buffer_chapter_2_it/

(after! org
  (defun tdh-render-org-table-at-point ()
    (interactive)
    (save-excursion
      (beginning-of-line)
      ;; removes the overlay is already there
      (if (overlays-at (point))
          (delete-overlay (car (overlays-at (point))))

        (let* ((element-type (org-element-type (org-element-at-point))))
          (if (and (not (eq element-type 'table))
                   (not (eq element-type 'table-row)))
              (error "not at an org table")

            (while (not (eq 'table (org-element-type (org-element-at-point))))
              (forward-line -1))
            (tdh-render-org-table (org-element-at-point))
            )))))


  (defun tdh-render-org-table (table)
    (interactive)
    (let* ((begin (org-element-property :begin table))
           (end (let ((pos (org-element-property :end table)))
                  (goto-char pos)
                  (beginning-of-line)
                  ;; skip possible space after table
                  (while (not (looking-at " *[|#]"))
                    (setq pos (point))
                    (forward-line -1))
                  pos))
           (tabletxt (buffer-substring-no-properties begin end))
           (img (with-temp-buffer
                  (insert tabletxt)
                  (mark-whole-buffer)
                  (org-latex-convert-region-to-latex)
                  (org-latex-preview)
                  (goto-char (point-min))
                  (overlay-get  (car (overlays-at (point))) 'display)))
           (overlay (make-overlay begin end)))
      (overlay-put overlay 'display img)
      (forward-line -1))
    )


  (defun tdh-render-org-tables-in-buffer ()
    (save-excursion
      (org-element-map (org-element-parse-buffer) 'table 'tdh-render-org-table)))

  ;; Use F9 to globally generate tables
  (map! :map org-mode-map :n "<f8>" (lambda () (interactive) (tdh-render-org-table-at-point)))
  )

Disable LaTeX fragments in table

(after! org
  ;; Toggle
  (defvar td/org-disable-latex-in-tables t
    "If non-nil, disable LaTeX preview inside Org tables.")
  
  (defun td/toggle-latex-in-tables ()
    (interactive)
    (setq td/org-disable-latex-in-tables
          (not td/org-disable-latex-in-tables))
    (message "Disable LaTeX preview in tables: %s"
             td/org-disable-latex-in-tables))
  
  (defun td/point-in-table-p (pos)
    "Check if position POS is inside an Org table."
    (save-excursion
      (goto-char pos)
      (org-at-table-p)))
  
  (defadvice! td/org-format-latex-ignore-tables (orig-fn &rest args)
    "Disable LaTeX preview inside Org tables."
    :around #'org-format-latex
    (let ((beg (nth 0 args))
          (end (nth 1 args)))
      ;; If toggle is OFF → run normally
      (if (not td/org-disable-latex-in-tables)
          (apply orig-fn args)
        ;; If this is NOT a user-initiated call (no buffer positions)
        ;; we need to check if we're currently inside a table
        (if (not (and (number-or-marker-p beg)
                      (number-or-marker-p end)))
            ;; Internal call: check if point is in a table
            (if (td/point-in-table-p (point))
                nil  ; Skip if in table
              (apply orig-fn args))  ; Process if not in table
          ;; User-initiated preview with buffer region
          ;; Temporarily narrow to exclude table lines, then process
          (save-restriction
            (narrow-to-region beg end)
            (goto-char (point-min))
            ;; Process each non-table section separately
            (let ((start (point-min)))
              (while (not (eobp))
                (if (org-at-table-p)
                    ;; Skip the entire table
                    (progn
                      ;; Process region before table
                      (when (< start (point))
                        (apply orig-fn (list start (point)) (cddr args)))
                      ;; Move past table
                      (org-table-end)
                      (setq start (point)))
                  ;; Move to next line
                  (forward-line 1)))
              ;; Process any remaining region after last table
              (when (< start (point-max))
                (apply orig-fn (list start (point-max)) (cddr args))))))))))

;; Optional keybinding
(map! :leader
      :desc "Toggle LaTeX preview inside Org tables"
      "t t" #'td/toggle-latex-in-tables)

Org CalDAV

(use-package! org-caldav
  :config
  (setq
   org-caldav-url "https://radicale.tdehaeze.xyz/tdehaeze"
   org-caldav-calendar-id "627e2bee-7d6a-49dc-128e-fc7a8aed1e8b"
   org-caldav-inbox "~/Cloud/org/inbox-calendar.org"
   org-caldav-files '("~/Cloud/org/inbox.org" "~/Cloud/org/home-tasks.org")
   org-icalendar-use-scheduled '(event-if-todo-not-done)
   org-icalendar-use-deadline '(event-if-todo-not-done)
   org-caldav-days-in-past 7
   org-icalendar-timezone "Europe/Paris"
   ))

Org Inline Task

(after! org
  (require 'org-inlinetask)
  )

Org Links

yt: Youtube Links

(after! org
  (setq yt-iframe-format
        ;; You may want to change your width and height.
        (concat "<div class=\"yt\"><iframe width=\"100%%\""
                " height=\"100%%\""
                " src=\"https://www.youtube.com/embed/%s\""
                " frameborder=\"0\""
                " allowfullscreen>%s</iframe></div>"))

  (org-add-link-type
   "yt"
   (lambda (handle)
     (browse-url
      (concat "https://www.youtube.com/embed/"
              handle)))
   (lambda (path desc backend)
     (cl-case backend
       (html (format yt-iframe-format
                     path (or desc "")))
       (md (format "{{< youtube %s >}}"
                   path))
       (latex (format "\\href{%s}{%s}"
                      (concat "https://www.youtube.com/embed/"
                              path) (or desc "video"))))))
  )

message: link to mutt

;; Customizable variables
(defcustom tdh/org-mutt-terminal "kitty"
  "The terminal emulator to use for opening Mutt/Neomutt."
  :group 'org-link
  :type 'string)

(defcustom tdh/org-mutt-executable "neomutt"
  "The Mutt/Neomutt executable name."
  :group 'org-link
  :type 'string)

(defcustom tdh/org-mutt-mu-utility "mu"
   "The 'mu' mail indexer executable name."
   :group 'org-link
   :type 'string)

(defun tdh/org-open-mutt-message (message-id)
  "Open the email with the given Message-ID in Mutt/Neomutt using 'mu'.

This function is intended to be called by Org mode for 'message://' links.
It uses `mu find` to locate the email file, determines the Maildir folder,
and launches Mutt/Neomutt in a terminal specified by `tdh/org-mutt-terminal`,
instructing it to limit view to the specific message.

The Message-ID should be passed without the 'message://' prefix and
without surrounding '<>' characters."
  (interactive "sMessage-ID: ") ; For testing interactively
  (let* (
         ;; 1. Sanitize Message-ID (remove potential whitespace or <>)
         (msg-id (replace-regexp-in-string "[<>[:space:]\n]" "" message-id))
         ;; 2. Construct the 'mu find' command safely
         (mu-find-command (format "%s find --nocolor -f l i:%s | head -n 1"
                                  (shell-quote-argument tdh/org-mutt-mu-utility)
                                  (shell-quote-argument msg-id))) ; Quote msg-id for shell
         ;; 3. Execute 'mu find' and get the mail file path
         (mail-file-raw (shell-command-to-string mu-find-command))
         ;; Trim leading/trailing whitespace and newlines from the result
         (mail-file (replace-regexp-in-string "\\`[[:space:]]*\\|[[:space:]]*\\'" "" mail-file-raw)))

    ;; 4. Check if 'mu find' returned a valid path
    (if (or (string-empty-p mail-file) (not (file-exists-p mail-file)))
        (error "Could not find mail file for Message-ID '%s'. Command: %s. Result: '%s'"
               msg-id mu-find-command mail-file-raw)

      ;; 5. Derive the Maildir *folder* from the file path
      (let* (
             ;; This regex assumes standard Maildir structure like /path/to/Maildir/cur/filename
             ;; It removes the "/cur/filename", "/new/filename", or "/tmp/filename" part.
             ;; Adjust if your Maildir structure or mu's output format differs.
             (mail-dir (replace-regexp-in-string "/\\(cur\\|new\\|tmp\\)/[^/]*$" "/" mail-file))
             ;; Alternative (simpler, maybe less robust): just get parent dir of the file
             ;; (mail-dir (directory-file-name (file-name-directory mail-file)))

             ;; 6. Define the keystrokes to send to Mutt/Neomutt
             ;;    L: Limit command
             ;;    ~i <ID>: Search Message-ID header
             ;;    \n: Execute limit
             ;;    \n: Press Enter again (should open the first/only message in the limited view)
             (mutt-keystrokes (format "L~i %s\n\n" msg-id)) ; Limit, Enter, Enter to open

             ;; 7. Prepare arguments for the terminal and Mutt/Neomutt
             (mutt-base-args (list "-R" ; Start read-only (safer, remove if you want write access)
                                   "-f" mail-dir
                                   "-e" (format "push '%s'" mutt-keystrokes)))
             ;; Command list for the terminal emulator
             (process-args (append (list "-e" tdh/org-mutt-executable) mutt-base-args))
             (process-name (concat tdh/org-mutt-executable "-" msg-id))) ; Unique process name for Emacs


        (message "Launching %s for message %s (Maildir: %s)" tdh/org-mutt-executable msg-id mail-dir)

        ;; 8. Launch the process asynchronously using start-process (doesn't block Emacs)
        (apply 'start-process process-name nil tdh/org-mutt-terminal process-args)

        ;; --- Alternative: Using call-process + setsid (might block Emacs briefly) ---
        ;; This combines the arguments differently because setsid takes the command first
        ;; (let ((full-command (append (list tdh/org-mutt-executable) mutt-base-args)))
        ;;   (apply 'call-process "setsid" nil nil "-f" tdh/org-mutt-terminal "-e" full-command))
        ))))

;; Register the link type handler with Org mode
(org-add-link-type "message" 'tdh/org-open-mutt-message t) ; Added 't' to force update if already defined

Org Wild Notifier

(use-package! org-wild-notifier
  :after org
  :init
  (setq alert-default-style 'libnotify)
  :config
  (setq org-wild-notifier-alert-time '(10 5))
  (setq org-wild-notifier-notification-title "Org Agenda")
  (org-wild-notifier-mode)
)

Custom Keybindings - , leader key and C-c

C-c a Org Agenda
C-c n Narrow to Subtree
C-c l Org Link
(after! org
  (map! :map org-mode-map
   (:desc "Org Agenda"
     :ni "C-c a" 'org-agenda)
   (:desc "Archive"
     :n "C-c A" 'org-archive-subtree)
   (:desc "Org Capture"
     :ni "C-c c" 'org-capture)
   (:desc "Store Link"
     :ni "C-c l" 'org-store-link)
   (:desc "Narrow Subtree"
     :ni "C-c n" 'org-toggle-narrow-to-subtree)
   (:desc "Org Noter"
     :ni "C-c N" 'org-noter)
   (:desc "Align Block"
     :ni "C-c =" 'tdh-align-src-block)
   (:desc "Insert Reference"
     :ni "C-c r" 'org-ref-insert-ref-link)
   (:desc "Insert Image"
     :ni "C-c i" 'tdh-insert-image-org-link)
   (:desc "Insert Image SXIV"
     :ni "C-c I" 'tdh-insert-image-org-link-sxiv)
   (:desc "Link to next Figure"
     :ni "C-c f" 'tdh-insert-link-to-next-figure)
   (:desc "Link to previous Figure"
     :ni "C-c F" 'tdh-insert-link-to-previous-figure)
   (:desc "Link to next Table"
     :ni "C-c t" 'tdh-insert-link-to-next-table)
   (:desc "Link to previous Table"
     :ni "C-c T" 'tdh-insert-link-to-previous-table)
   (:desc "Insert Screenshot"
     :ni "C-c s" 'tdh-insert-screenshot-org-link)
   (:desc "Insert Screenshot"
     :ni "C-c R" 'org-roam-node-find)
   (:desc "Helm Bibtex"
     :ni "C-c ]" 'org-ref-cite-insert-helm)
   ))

Insert Elements ,i

Insert Link to paper

(defun tdh-insert-paper-org-link (paper)
  "Insert an org link to some paper, choosing the file with completion"
  (interactive
   (list (read-file-name "Paper: " "~/Cloud/pdfs/" nil t)))
  (insert (format "[[papers:%s]]" (file-name-base paper))))

Insert Link to notes

(defun tdh-insert-note-org-link (note)
  "Insert an org link to some note, choosing the file with completion"
  (interactive
   (list (read-file-name "Note: " "~/Cloud/pdfs/" nil t)))
  (insert (format "[[notes:%s]]" (file-name-base note))))

Insert Image that is in the figs folder

(defun tdh-insert-image-org-link (img)
  "Insert an org image link, choosing the file with completion
and starting from `my-default-image-directory'."
  (interactive
   (list (file-relative-name (read-file-name "Image: " (concat default-directory "figs/")) default-directory)))
  (insert (format "[[file:%s]]" img)))

Insert Image that is in the figs folder using SXIV

(defun tdh-insert-image-org-link-sxiv ()
  "Insert an org image link, choosing the file with completion
and starting from `my-default-image-directory'."
  (interactive)
  (setq img (shell-command-to-string "ls figs/*.{jpg,jpeg,bmp,png,gif} 2> /dev/null | nsxiv -i -t -o | tail -1 | tr -d '\n'"))
  (unless (equal "" img)
    (insert (format "[[file:%s]]" img)))
  )

Copy picture from phone folder using SXIV and insert it

(defun tdh-insert-phone-picture ()
  (interactive)
  (setq img (shell-command-to-string "~/.config/doom/bin/copy-phone-picture.sh"))
  (unless (equal "" img)
    (insert (format "[[file:%s]]" img)))
  )

Bash script for copying pictures taken by phone.

if [ -z "$1" ]; then
    oldpath=$(ls -t ~/Cloud/photos/phone/*.jpg | nsxiv -i -t -o | tail -1);
else
    oldpath=$(ls -t $1 | nsxiv -i -t -o | tail -1);
fi

if [ -n "$oldpath" ]; then
    newfilename=$(basename $oldpath .jpg | rofi -i -dmenu -p "Filename")
    if [ -n "$newfilename" ]; then
        cp $oldpath "figs/$newfilename.jpg"
        printf "figs/$newfilename.jpg"
    fi
fi

Take Screenshot and insert a link:

  • Ask for a name screenshot_name
  • use maim -s figs/screenshot_name.png to take a screenshot with selection
  • Then insert the following to the buffer
(defun tdh-insert-screenshot-org-link ()
  "Capture screenshot and insert the resulting file.
The screenshot tool is determined by `org-download-screenshot-method'."
  (interactive)
  (if (string-match "_" (file-name-base buffer-file-name))
      (setq filename (read-string "Enter file name:" (car (split-string (file-name-base buffer-file-name) "_"))))
    (setq filename (read-string "Enter file name:")))
  (setq filepath (concat "./figs/" filename ".png"))
  (shell-command (concat "maim -u -s " filepath))
  (insert (format "#+name: fig:%s\n#+caption:\n[[file:%s]]" filename filepath))
  (search-backward "caption")
  (end-of-line)
  )

Insert link to next figure:

(defun tdh-insert-link-to-next-figure ()
  (interactive)
  (save-excursion
    (re-search-forward "^#\\+name:\s*\\(fig:.*\\)" nil t 1))
  (insert (concat "ref:" (match-string 1)))
  )

Insert link to previous figure:

(defun tdh-insert-link-to-previous-figure ()
  (interactive)
  (save-excursion
    (re-search-backward "^#\\+name:\s*\\(fig:.*\\)" nil t 1))
  (insert (concat "ref:" (match-string 1)))
  )

Insert link to next table:

(defun tdh-insert-link-to-next-table ()
  (interactive)
  (save-excursion
    (re-search-forward "^#\\+name:\s*\\(tab:.*\\)" nil t 1))
  (insert (concat "ref:" (match-string 1)))
  )

Insert link to previous table:

(defun tdh-insert-link-to-previous-table ()
  (interactive)
  (save-excursion
    (re-search-backward "^#\\+name:\s*\\(tab:.*\\)" nil t 1))
  (insert (concat "ref:" (match-string 1)))
  )

Map Keys

(after! org
  (map! :map org-mode-map
        (:prefix (",i" . "Insert")
        :n "p" 'tdh-insert-paper-org-link
        :n "n" 'tdh-insert-note-org-link
        :n "f" 'tdh-insert-image-org-link
        :n "F" 'tdh-insert-image-org-link-sxiv
        :n "i" 'tdh-insert-phone-picture
        :n "l" 'tdh-insert-link-to-next-figure
        :n "L" 'tdh-insert-link-to-previous-figure
        :n "s" 'tdh-insert-screenshot-org-link)))

LaTeX ,l

(defun tdh-latex-watch ()
  "Watch LaTeX file using latexmk"
  (interactive)
  (start-process-shell-command "latexmk-watch" "*latexmk-watch-output*"
                               "latexmk -bibtex -pvc"))
(defun tdh-latex-watch-kill ()
  "Kill the currently running TeX job."
  (interactive)
  (delete-process "latexmk-watch")
  )
(after! org
  (map! :map org-mode-map
        (:prefix (",l" . "LaTeX")
        :n "w" 'tdh-latex-watch
        :n "k" 'tdh-latex-watch-kill
        :n "l" 'org-latex-export-to-latex)))

Org LaTeX Automatic fragment

(use-package! org-fragtog
  :after org
  :config
  (add-hook 'org-mode-hook 'org-fragtog-mode)
)
(defun tdh-automatic-latex-fragment-activate ()
  (interactive)
  (add-hook 'org-mode-hook 'org-fragtog-mode))

(defun tdh-automatic-latex-fragment-deactivate ()
  (interactive)
  (remove-hook 'org-mode-hook 'org-fragtog-mode))
(after! org
  (map! :map org-mode-map
        (:prefix (",l" . "LaTeX")
        :n "f" 'tdh-automatic-latex-fragment-activate
        :n "F" 'tdh-automatic-latex-fragment-deactivate)))

Org-Appear

(use-package! org-appear
  :after org
  :hook (org-mode . org-appear-mode)
  :config (setq
           org-appear-autolinks t
           org-appear-autoentities t
           org-appear-autosubmarkers t ))

Bibtex ,r

(after! org
  (map! :map org-mode-map
        (:prefix (",r" . "References")
        :n "b" 'helm-bibtex
        :n "B" 'helm-bibtex-with-local-bibliography
        :n "f" 'tdh-helm-bibtex-favorites
        :n "r" 'helm-resume)))

Open yazi in current directory ,o

(defun tdh-open-yazi-in-workdir ()
  (interactive)
  (call-process-shell-command
  (concat "kitty -e yazi " default-directory) nil 0))
(after! org
  (map! :map org-mode-map
        :n ",o" 'tdh-open-yazi-in-workdir))

View in External programs ,v

Open PDF output with zathura

(defun tdh-open-org-pdf-externally ()
  (interactive)
  (call-process "zathura" nil 0 nil (concat (file-name-sans-extension (buffer-file-name)) ".pdf"))
  )

Open HTML output externally

(defun tdh-open-org-html-externally ()
    (interactive)
    (call-process "xdg-open" nil 0 nil (concat (file-name-sans-extension (buffer-file-name)) ".html"))
    )
(after! org
  (map! :map org-mode-map
        (:prefix (",v" . "View")
        :n "p" 'tdh-open-org-pdf-externally
        :n "h" 'tdh-open-org-html-externally)))

Org Babel

Main configuration

Don't ask for confirmation when evaluating following blocs

(defun tdh-org-confirm-babel-evaluate (lang body)
  (not (member lang '("emacs-lisp" "latex" "matlab" "sh" "latex-macros" "python" "ipython" "jupyter-python" "dot"))))

(after! org
  (setq org-confirm-babel-evaluate 'tdh-org-confirm-babel-evaluate))

Default header arguments.

(after! org
  (setq org-babel-default-header-args '((:eval . "no-export"))))

Use the current window for C-c ' source editing

(after! org
  (setq org-src-window-setup 'current-window))

Appearance of source blocks

(defun tdh-org-prettify-symbols ()
  (mapc (apply-partially 'add-to-list 'prettify-symbols-alist)
        (cl-reduce 'append
                   (mapcar (lambda (x) (list x (cons (upcase (car x)) (cdr x))))
                           `(("#+begin_src" . ?✎)
                             ("#+end_src"   . ?□)
                             ("#+begin_quote" . )
                             ("#+end_quote" . )))))
  (turn-on-prettify-symbols-mode))
(add-hook 'org-mode-hook #'tdh-org-prettify-symbols)

Indentation

(after! org
  ;; Don't change indentation when toggling
  (setq org-src-preserve-indentation t)
  )

Library of Babel

Add all named source blocks to org-babel-library-of-babel (link).

(after! org
  (org-babel-lob-ingest "~/.config/literate-dotfiles/emacs-library-babel.org"))

Org-Babel Matlab

(after! org
  (setq org-babel-matlab-shell-command "~/.local/bin/matlab -softwareopengl -nodesktop -nosplash")
  )

Default options for Matlab code

(after! org
  (setq org-babel-default-header-args:matlab
        '((:results . "none")
          (:session . "*MATLAB*")
          (:comments . "org")
          (:exports . "both")
          (:cache .   "no")
          (:noweb . "no")
          (:hlines . "no")
          (:tangle . "yes")
          (:mkdir . "yes")
          (:eval . "no-export")))
  )

Better format the output results for Matlab (link).

(after! org
  (setq org-babel-octave-wrapper-method
    "%s
  if ischar(ans), fid = fopen('%s', 'w'); fprintf(fid, '%%s\\n', ans); fclose(fid);
  else, save -ascii %s ans
  end
  ")
  (defun org-babel-octave-evaluate-session
      (session body result-type &optional matlabp)
    "Evaluate BODY in SESSION."
    (let* ((tmp-file (org-babel-temp-file (if matlabp "matlab-" "octave-")))
           (wait-file (org-babel-temp-file "matlab-emacs-link-wait-signal-"))
           (full-body
            (pcase result-type
              (`output
               (mapconcat
                #'org-babel-chomp
                (list (if matlabp
                          (multi-replace-regexp-in-string
                           '(("%.*$"                      . "")    ;Remove comments
                             (";\\s-*\n+"                 . "; ")  ;Concatenate lines
                             ("\\(\\.\\)\\{3\\}\\s-*\n+"  . " ")   ;Handle continuations
                             (",*\\s-*\n+"                . ", ")) ;Concatenate lines
                           body)
                        body)
                      org-babel-octave-eoe-indicator) "\n"))
              (`value
               (if (and matlabp org-babel-matlab-with-emacs-link)
                   (concat
                    (format org-babel-matlab-emacs-link-wrapper-method
                            body
                            (org-babel-process-file-name tmp-file 'noquote)
                            (org-babel-process-file-name tmp-file 'noquote) wait-file) "\n")
                 (mapconcat
                  #'org-babel-chomp
                  (list (format org-babel-octave-wrapper-method
                                body
                                (org-babel-process-file-name tmp-file 'noquote)
                                (org-babel-process-file-name tmp-file 'noquote))
                        org-babel-octave-eoe-indicator) "\n")))))
           (raw (if (and matlabp org-babel-matlab-with-emacs-link)
                    (save-window-excursion
                      (with-temp-buffer
                        (insert full-body)
                        (write-region "" 'ignored wait-file nil nil nil 'excl)
                        (matlab-shell-run-region (point-min) (point-max))
                        (message "Waiting for Matlab Emacs Link")
                        (while (file-exists-p wait-file) (sit-for 0.01))
                        "")) ;; matlab-shell-run-region doesn't seem to
                  ;; make *matlab* buffer contents easily
                  ;; available, so :results output currently
                  ;; won't work
                  (org-babel-comint-with-output
                      (session
                       (if matlabp
                           org-babel-octave-eoe-indicator
                         org-babel-octave-eoe-output)
                       t full-body)
                    (insert full-body) (comint-send-input nil t)))) results)
      (pcase result-type
        (`value
         (org-babel-octave-import-elisp-from-file tmp-file))
        (`output
         (setq results
               (if matlabp
                   (cdr (reverse (delete "" (mapcar #'org-strip-quotes
                                                    (mapcar #'org-trim (remove-car-upto-newline raw))))))
                 (cdr (member org-babel-octave-eoe-output
                              (reverse (mapcar #'org-strip-quotes
                                               (mapcar #'org-trim raw)))))))
         (mapconcat #'identity (reverse results) "\n")))))

  (defun remove-car-upto-newline (raw)
    "Truncate each string in a list of strings up to the first newline"
    (cons (mapconcat #'identity
                     (cdr (split-string-and-unquote (car raw) "\n"))
                     "\n") (cdr raw)))

  (defun multi-replace-regexp-in-string (replacements-list string &optional rest)
    (interactive)
    "Replace multiple regexps in a string. Order matters."
    (if (null replacements-list)
        string
      (let ((regex (caar replacements-list))
            (replacement (cdar replacements-list)))
        (multi-replace-regexp-in-string (cdr replacements-list)
                                        (replace-regexp-in-string regex replacement
                                                                  string rest)))))
  )

Some functions for using Matlab with Org Babel ,m

whos matlab function

(defun tdh-matlab-whos (&optional start end)
"Get what is in the Matlab workspace"
  (interactive)
  (if (use-region-p)
    (let ((regionp (buffer-substring (region-beginning) (region-end))))
      (process-send-string "*MATLAB*" (concat "whosEmacs " regionp "\n")))
    (process-send-string "*MATLAB*" (concat "whosEmacs" "\n"))))

help matlab function

(defun tdh-matlab-help (&optional start end)
  "Get help on the selected function"
  (interactive)
  (if (use-region-p)
    (let ((regionp (buffer-substring (region-beginning) (region-end))))
        (process-send-string "*MATLAB*" (concat "help " regionp "\n")))
    (process-send-string "*MATLAB*" (concat "help " (read-string "Matlab help:") "\n")))
  )

Specify a Matlab command to run

(defun tdh-matlab-run-command ()
"Prompt user to enter a matlab command"
(interactive)
(process-send-string "*MATLAB*" (concat (read-string "Matlab Command: ") "\n")))

Specify a Matlab command to run and show output in mini-buffer

(defun tdh-matlab-run-command-show-output ()
  "Prompt user to enter a matlab command"
  (interactive)
  (process-send-string "*MATLAB*" (concat "evalEmacs('" (read-string "Matlab Command: ") "')\n")))

Org-Babel Tangle File and Execute with Matlab

(defun tdh-matlab-tangle-and-execute ()
"Jump to tangle file for the source block at point."
(interactive)
(let (file org-babel-pre-tangle-hook org-babel-post-tangle-hook)
  (cl-letf (((symbol-function 'write-region) (lambda (start end filename &rest _ignore)
                       (setq file filename)))
        ((symbol-function 'delete-file) #'ignore))
    (org-babel-tangle '(4)))
  (when file
    (setq file (expand-file-name file))
    (if (file-readable-p file)
    (process-send-string "*MATLAB*" (concat "run " file "\n"))
  (error "Cannot open tangle file %S" file)))))

Map Functions

(after! org
  (map! :map org-mode-map
        (:prefix (",m" . "Matlab")
        :n  "e" 'tdh-matlab-run-command
        :n  "E" 'tdh-matlab-run-command-show-output
        :n  "T" 'tdh-matlab-tangle-and-execute
        :nv "h" 'tdh-matlab-help
        :nv "w" 'tdh-matlab-whos)))

Remap ctrl-ret used to execute the src block and go to the next one

https://emacs.stackexchange.com/questions/13869/how-to-toggle-org-mode-source-code-block-eval-no-status

Remap ctrl-ret to execute the source block and go to the next source block when inside a source block. Otherwise, keep the normal behavior for ctrl-ret.

(defun tdh-ctrl-ret ()
  (interactive)
  (defun tdh-in-src-block-p ()
    "Returns t when the point is inside a source code block"
    (string= "src" (org-in-block-p '("src"))))

  (if (tdh-in-src-block-p)
      (progn
        (org-babel-execute-src-block)
        (org-babel-next-src-block))
    (+org--insert-item 'below)))
(map! :after evil-org
      :map evil-org-mode-map
      :n "<C-return>" #'tdh-ctrl-ret)

Remap ctrl-shift-ret used to execute the (matlab) src block in the background and go to the next one

tdh-org-babel-execute-matlab-background

(defun tdh-org-babel-execute-matlab-background (&optional arg info params)
  (interactive)
  (let* ((org-babel-current-src-block-location
      (or org-babel-current-src-block-location
          (nth 5 info)
          (org-babel-where-is-src-block-head)))
     (info (if info (copy-tree info) (org-babel-get-src-block-info))))
    ;; Merge PARAMS with INFO before considering source block
    ;; evaluation since both could disagree.
    (cl-callf org-babel-merge-params (nth 2 info) params)
    (when (org-babel-check-evaluate info)
      (cl-callf org-babel-process-params (nth 2 info))
      (let* ((params (nth 2 info))
         (cache (let ((c (cdr (assq :cache params))))
              (and (not arg) c (string= "yes" c))))
         (new-hash (and cache (org-babel-sha1-hash info :eval)))
         (old-hash (and cache (org-babel-current-result-hash)))
         (current-cache (and new-hash (equal new-hash old-hash))))
    (cond
     (current-cache
      (save-excursion		;Return cached result.
        (goto-char (org-babel-where-is-src-block-result nil info))
        (forward-line)
        (skip-chars-forward " \t")
        (let ((result (org-babel-read-result)))
          (message (replace-regexp-in-string "%" "%%" (format "%S" result)))
          result)))
     ((org-babel-confirm-evaluate info)
      (let* ((lang (nth 0 info))
         (result-params (cdr (assq :result-params params)))
         ;; Expand noweb references in BODY and remove any
         ;; coderef.
         (body
          (let ((coderef (nth 6 info))
            (expand
             (if (org-babel-noweb-p params :eval)
                 (org-babel-expand-noweb-references info)
               (nth 1 info))))
            (if (not coderef) expand
              (replace-regexp-in-string
               (org-src-coderef-regexp coderef) "" expand nil nil 1))))
         (dir (cdr (assq :dir params)))
         (mkdirp (cdr (assq :mkdirp params)))
         (default-directory
           (cond
            ((not dir) default-directory)
            ((member mkdirp '("no" "nil" nil))
             (file-name-as-directory (expand-file-name dir)))
            (t
             (let ((d (file-name-as-directory (expand-file-name dir))))
               (make-directory d 'parents)
               d))))
         (cmd (intern (concat "org-babel-execute:" lang)))
         result)
        (process-send-string "*MATLAB*" (concat body "\n"))
        result))
     )))
    )
  )

tdh-matlab-execute-selected

(defun tdh-matlab-execute-selected (start end)
"Execute selected text in the *MATLAB* buffer"
  (interactive "r")
  (let ((regionp (buffer-substring start end)))
      (process-send-string "*MATLAB*" (concat regionp "\n"))))

Remap ctrl-shift-ref

This function:

  • first check if inside a source block, if not does nothing
  • when check if the language is matlab

    • if it is not, it just runs the code and go to the next source block
    • if it is in a matlab block, it first check if a region if selected, if so it just runs the selected region. if no region is selected, it runs all the code blocks and goes to the next block
(defun tdh-ctrl-shift-ret ()
  (interactive)
  (defun tdh-in-src-block-p ()
    "Returns t when the point is inside a source code block"
    (string= "src" (org-in-block-p '("src"))))

  (if (tdh-in-src-block-p)
      (let ((lang (nth 0 (org-babel-get-src-block-info))))
        (if (string= lang "matlab")
            (if (region-active-p)
                (tdh-matlab-execute-selected (region-beginning) (region-end))
              (progn (tdh-org-babel-execute-matlab-background)))
          (org-babel-next-src-block))
        (if (string= lang "jupyter-python")
            (org-babel-execute-maybe)
          (org-babel-next-src-block))
        )
    (org-babel-next-src-block)
    )
  )
(map! :after evil-org
      :map evil-org-mode-map
      :n "<C-S-return>" #'tdh-ctrl-shift-ret)

Align Source Blocks

(defun tdh-align-src-block ()
  (interactive)
  (defun tdh-in-src-block-p ()
    "Returns t when the point is inside a source code block"
    (string= "src" (org-in-block-p '("src"))))

  (if (tdh-in-src-block-p)
      (progn
        (org-edit-special)
        (indent-region (point-min) (point-max))
        (org-edit-src-exit))
    (org-table-eval-formula)))

Helping Functions - Tangling ,b

Org-Babel Tangle Sub-tree

(defun tdh-org-babel-tangle-subtree ()
  "Tangle the current subtree"
  (interactive)
  (progn
    (org-narrow-to-subtree)
    (org-babel-tangle)
    (widen))
  )

Org-Tangle and Org-Babel Jump to Tangle File

(defun tdh-org-babel-jump-to-tangle-file ()
  "Jump to tangle file for the source block at point."
  (interactive)
  (let (file org-babel-pre-tangle-hook org-babel-post-tangle-hook)
    (cl-letf (((symbol-function 'write-region) (lambda (start end filename &rest _ignore)
                                                 (setq file filename)))
              ((symbol-function 'delete-file) #'ignore))
      (org-babel-tangle '(4)))
    (when file
      (setq file (expand-file-name file))
      (if (file-readable-p file)
          (find-file file)
        (error "Cannot open tangle file %S" file)))))
(defun tdh-org-babel-tangle-block ()
  (interactive)
  (let ((current-prefix-arg '(4)))
    (call-interactively 'org-babel-tangle)
    ))

Map Functions

(after! org
  (map! :map org-mode-map
        (:prefix (",b" . "Tangle")
        :n  "F" 'tdh-org-babel-jump-to-tangle-file
        :n  "b" 'tdh-org-babel-tangle-block
        :n  "T" 'tdh-org-babel-tangle-subtree)))

Bibliography Management

My bibliography management is mainly based on the following packages:

  • org-ref for nice citations
  • org-noter to annotate documents
  • org-roam to manage and links all my notes
  • helm-bibtex as an interface to easily find references
  • org-roam-bibtex that connects all the above packages

Org Ref (link)

Nice Functions:

  • org-ref-insert-ref-link
  • org-ref-helm-insert-cite-link
  • org-ref-list-of-figures
  • org-ref-find-bad-citations
  • org-ref-clean-bibtex-entry
(use-package! org-ref
  :after org
  :config
  ;; Ox-Hugo configuration: https://ox-hugo.scripter.co/doc/org-ref-citations/
  (setq org-hugo-link-desc-insert-type t)

  ;; Folder where the notes files are located (or file if just one Note file)
  (setq bibtex-completion-notes-path "~/Cloud/brain/")

  ;; Bibliography File
  (setq bibtex-completion-bibliography '("~/Cloud/brain/biblio/references.bib"))

  ;; Folder where all the pdf are located
  (setq bibtex-completion-library-path '("~/Cloud/pdfs/"))

  (setq org-ref-bibliography-entry-format
        '(("article" . "%a, %t, %j, v(%n), %p (%y).")
          ("book" . "%a, %t, %u (%y).")
          ("techreport" . "%a, %t, %i, %u (%y).")
          ("phdthesis" . "%a, %t (%y).")
          ("proceedings" . "%e, %t in %S, %u (%y).")
          ("inproceedings" . "%a, %t, %p, in %b, edited by %e, %u (%y)")))

  ;; Tell org-ref to let helm-bibtex find notes for it
  (setq org-ref-notes-function
        (lambda (thekey)
          (let ((bibtex-completion-bibliography (org-ref-find-bibliography)))
            (bibtex-completion-edit-notes
             (list (car (org-ref-get-bibtex-key-and-file thekey)))))))

  ;; Problem with speed: don't display broken links
  (setq org-ref-show-broken-links t)
  ;; Display information on the citation
  (setq org-ref-show-citation-on-enter t)

  ;; Remove hook that tries do get PDF each time...
  (remove-hook 'org-ref-clean-bibtex-entry-hook 'orcb-download-pdf)

  ;; (add-to-list 'org-ref-helm-user-candidates
  ;;              '("Open pdf in Zathura" . (lambda () (call-process "zathura" nil 0 nil  (concat
  ;;                                                                                       (file-name-as-directory org-ref-pdf-directory)
  ;;                                                                                       (car (org-ref-get-bibtex-key-and-file))
  ;;                                                                                       ".pdf"))))
  ;;              t)

  ;; (add-to-list 'org-ref-helm-user-candidates
  ;;              '("Drag and Drop" . (lambda () (call-process "/bin/bash" nil 0 nil "-c" (concat
  ;;                                                                                       "dragon "
  ;;                                                                                       (file-name-as-directory org-ref-pdf-directory)
  ;;                                                                                       (car (org-ref-get-bibtex-key-and-file))
  ;;                                                                                       ".pdf"))))
  ;;              t)

  ;; Let Mathjax deals with equation reference
  ;; TODO - Will use an advice instead
  ;; (defun org-ref-eqref-export (keyword desc format)
  ;;   (cond
  ;;    ((eq format 'latex) (format "\\eqref{%s}" keyword))
  ;;    ((eq format 'html) (format "\\eqref{%s}" keyword))
  ;;    ((eq format 'md) (format "\\eqref{%s}" keyword))))

  ;; Convert eqref:label to \eqref{label}
  (defun my/replace-eqref-with-ref (backend)
    "Replace eqref:label with \\ref{label} for HTML and Hugo export."
    (when (memq backend '(html html5 hugo))
      (goto-char (point-min))
      (while (re-search-forward "eqref:\\([a-zA-Z0-9:-_]+\\)" nil t)
        (replace-match "\\\\ref{\\1}"))))

  (add-hook 'org-export-before-processing-hook 'my/replace-eqref-with-ref)

  ;; Derived from org-ref-extract-bibtex-to-file to force the bibfile to have the same name than to org file, and take references from bibtex-completion-bibliography
  ;; this function can be added in the org-export-before-parsing-hook for instance
  (defun tdh-org-ref-extract-bibtex-to-file (&optional arg)
    "Extract all bibtex entries for citations buffer to BIBFILE.
If BIBFILE exists, append, unless you use a prefix arg (C-u),
which will CLOBBER the file."
    (interactive)
    (let* ((bibtex-files bibtex-completion-bibliography)
           (bibfile (file-name-nondirectory
                     (concat (file-name-sans-extension
                              (buffer-file-name))
                             ".bib")))
           (keys (reverse (org-ref-get-bibtex-keys)))
           (bibtex-entry-kill-ring-max (length keys))
           (bibtex-entry-kill-ring '())
           (kill-cb (not (find-buffer-visiting bibfile)))
           (cb (find-file-noselect bibfile))
           (current-bib-entries (with-current-buffer cb
                                  (prog1
                                      (buffer-string)
                                    (when kill-cb (kill-buffer cb))))))

      (save-window-excursion
        (cl-loop for key in keys
                 do
                 (bibtex-search-entry key t)
                 (bibtex-kill-entry t)))

      (with-temp-file bibfile
        (insert (mapconcat
                 'identity
                 bibtex-entry-kill-ring
                 "\n\n")))))
  )
(after! org
  (require 'org-ref))
(defun tdh-org-ref-open-pdf-at-point ()
  "Open the pdf in external program for bibtex key under point if it exists."
  (interactive)
  (let* ((results (org-ref-get-bibtex-key-and-file))
         (key (car results))
         (pdf-file (funcall org-ref-get-pdf-filename-function key)))
    (if (file-exists-p pdf-file)
        (call-process "zathura" nil 0 nil pdf-file)
      (message "no pdf found for %s" key))))


;; Open with Zathura by default
(setq org-ref-open-pdf-function 'tdh-org-ref-open-pdf-at-point)
(after! org
  (defun tdh-org-ref-import-pdf (doi file)
    (doi-utils-add-bibtex-entry-from-doi doi "~/Cloud/brain/biblio/references.bib")
    (save-excursion
      (find-file "~/Cloud/brain/biblio/references.bib")
      (goto-char (point-max))
      (bibtex-beginning-of-entry)
      (let* ((bibtex-expand-strings t)
             (entry (bibtex-parse-entry t))
             (key (cdr (assoc "=key=" entry)))
             pdf)
        (if (bibtex-completion-find-pdf-in-library key)
            (message (format "A file named %s already exists" (bibtex-completion-find-pdf-in-library key)))
          (setq pdf (expand-file-name (concat key ".pdf") (cond
                                                           ((stringp bibtex-completion-library-path)
                                                            bibtex-completion-library-path)
                                                           ((and (listp bibtex-completion-library-path)
                                                                 (= 1 (length bibtex-completion-library-path)))
                                                            (car bibtex-completion-library-path))
                                                           (t
                                                            (completing-read "Dir: " bibtex-completion-library-path)))))
          (rename-file file pdf)
          (message (format "Created file %s" pdf))))))
  )

Org Noter (link)

(use-package! org-noter
  :defer t
  :after (:any org pdf-view)
  :config
  (setq org-noter-always-create-frame nil)

  (setq org-noter-kill-frame-at-session-end nil)

  ;; Fraction of the frame that the document window will occupy when split
  (setq org-noter-doc-split-fraction '(0.6 . 0.6))

  ;; Save the last visited location automatically; when starting a new session, go to that location
  (setq org-noter-auto-save-last-location nil)

  ;; Add an empty line between each note's heading and content
  (setq org-noter-separate-notes-from-heading t)

  ;; List of paths to check (non recursively) when searching for a notes file
  (setq org-noter-notes-search-path "~/Cloud/brain")

  (defun org-noter-init-pdf-view ()
    (pdf-view-fit-page-to-window)
    (pdf-view-auto-slice-minor-mode)
    (run-at-time "0.5 sec" nil #'org-noter))
  (add-hook 'pdf-view-mode-hook 'org-noter-init-pdf-view)

  (map!
   :map pdf-view-mode-map
   (:desc "Insert Note"
     :n "i" #'org-noter-insert-note))
  )

Capture Templates

Bibliography

- Tags :: %?
- Reference :: ${ref}
- Author(s) :: %^{author}
- Year :: %^{year}


* %^{author-abbrev} (%^{year}): %^{title} :%^{entry-type}:ignore:
:PROPERTIES:
:NOTER_DOCUMENT: ../pdfs/%^{citekey}.pdf
:END:

* Bibliography
bibliography:./biblio/references.bib

Default

- Tags ::

%?

* Bibliography
bibliography:./biblio/references.bib

Org Roam (link)

(use-package! org-roam
  :custom-face
  (org-roam-link ((t (:inherit org-link :foreground "#cc241d"))))
  :config
  (setq org-roam-directory (file-truename "~/Cloud/brain/"))
  (make-directory org-roam-directory 'parents)
  (setq org-roam-completion-system 'helm)
  (setq org-roam-tag-sources '(prop last-directory))

  (setq org-roam-capture-templates
        `(("d" "default" plain (file "~/.config/doom/capture-templates/default.org")
           :if-new (file+head "${slug}.org" "#+title: ${title}\n#+setupfile: ./setup/org-setup-file.org\n#+hugo_section: zettels\n\n")
           :unnarrowed t)
          ("r" "bibliography reference" plain (file "~/.config/doom/capture-templates/ref.org")
           :if-new (file+head "${citekey}.org" "#+title: ${title}\n#+setupfile: ./setup/org-setup-file.org\n#+hugo_section: ${entry-type}\n\n")
           :unnarrowed t)))
  )

Automatic export of backlinks

(after! (org org-roam org-ref)
  ;; (defun tdh-org-roam--backlinks-list (file)
  ;;   (when (org-roam--org-roam-file-p file)
  ;;     (mapcar #'car (org-roam-db-query [:select :distinct [from]
  ;;                                       :from links
  ;;                                       :where (= to $s1)
  ;;                                       :and from :not :like $s2] file "%private%"))))

  ;; (defun tdh-org-export-preprocessor (_backend)
  ;;   (when-let ((links (tdh-org-roam--backlinks-list (buffer-file-name))))
  ;;     (insert "\nBacklinks:\n")
  ;;     (dolist (link links)
  ;;       (insert (format "- [[file:%s][%s]]\n"
  ;;                       (file-relative-name link org-roam-directory)
  ;;                       (org-roam--get-title-or-slug link))))))

  ;; (add-hook 'org-export-before-processing-hook #'tdh-org-export-preprocessor)
  )

Correctly export references for Hugo blog.

(after! (org org-roam org-ref)
  ;; Citation processing for org-ref
  (defun tdh-org-export-org-ref-preprocessor--html (backend)
    "Preprocess `org-ref' citations to HTML format."
    (when (org-export-derived-backend-p backend 'html)
      (org-ref-process-buffer 'html)))

  (add-hook 'org-export-before-processing-hook #'tdh-org-export-org-ref-preprocessor--html)
  )

Re-Export all roam files.

(defun tdh-org-roam-export-all ()
  "Re-exports all Org-roam files to Hugo markdown."
  (interactive)
  (dolist (f (org-roam--list-files "~/Cloud/brain/"))
    (with-current-buffer (find-file f)
      (when (s-contains? "SETUPFILE" (buffer-string))
        (org-hugo-export-wim-to-md)))))

Helm-Bibtex (link)

(use-package! helm-bibtex
  :after-call helm-bibtex
  :init
  :config
  ;; Bibliography file
  (setq bibtex-completion-bibliography '("~/Cloud/brain/biblio/references.bib"))

  ;; Directory with all the pdfs
  (setq bibtex-completion-library-path '("~/Cloud/pdfs/"))

  ;; Directory with notes files
  (setq bibtex-completion-notes-path "~/Cloud/brain/")
  (setq bibtex-completion-notes-extension ".org")
  (setq bibtex-completion-pdf-extension '(".pdf" ".djvu"))

  (setq bibtex-completion-additional-search-fields '(keywords))

  ;; Use "keywords" field when looking for bib entries
  (setq helm-bibtex-additional-search-fields '(keywords))

  (setq helm-bibtex-full-frame nil)

  ;; Display of bibtex entries with helm
  (setq bibtex-completion-display-formats
        '((t . "${author:36} ${title:*} ${year:4} ${=type=:7} ${=has-note=:1}")))

  ;; Special symbols for notes and pdf
  (setq bibtex-completion-pdf-symbol "⌘")
  (setq bibtex-completion-notes-symbol "✎")

  ;; custom function for helm-bibtex
  (defun tdh-bibtex-completion-format-citation-cite (keys)
  "Format cite references for keys in KEYS."
  (s-join ", "
          (--map (format "cite:%s" it) keys)))

  (setq bibtex-completion-format-citation-functions
    '((org-mode      . tdh-bibtex-completion-format-citation-cite)
      (latex         . bibtex-completion-format-citation-cite)
      (default       . bibtex-completion-format-citation-default)))

  ;; Template used when creating new Note file
  (setq bibtex-completion-notes-template-multiple-files (concat "#+title: ${title}\n"
                                                                "#+setupfile: ./setup/org-setup-file.org\n"
                                                                "#+hugo_section: ${=type=}\n"
                                                                "#+roam_key: ${=key=}\n"
                                                                "#+hugo_draft: true\n"
                                                                "\n"
                                                                "- Tags ::\n"
                                                                "- Reference :: cite:${=key=}\n"
                                                                "- Author(s) :: ${author}\n"
                                                                "- Year :: ${year}\n"
                                                                "\n"
                                                                "* ${author-abbrev} (${year}): ${title} :${=type=}:ignore:\n"
                                                                ":PROPERTIES:\n"
                                                                ":NOTER_DOCUMENT: ../pdfs/${=key=}.pdf\n"
                                                                ":END:\n"
                                                                "\n"
                                                                "* Bibliography                                                        :ignore:\n"
                                                                "bibliography:./biblio/references.bib"
                                                                ))

  ;; Make "Edit notes" the default action
  (helm-delete-action-from-source "Edit notes" helm-source-bibtex)
  (helm-add-action-to-source "Edit notes" 'helm-bibtex-edit-notes helm-source-bibtex 0)

  (helm-delete-action-from-source "Open PDF Externally" helm-source-bibtex)
  (helm-add-action-to-source "Open PDF Externally" 'tdh-open-pdf-externally helm-source-bibtex 1)

  (helm-add-action-to-source "Insert Link to Note" 'tdh-insert-link-to-note helm-source-bibtex 2)

  (helm-add-action-to-source "Insert E-Reader Link" 'tdh-insert-link-to-pdf-entry helm-source-bibtex 3)
  )
(defun tdh-insert-link-to-pdf-entry (key)
  "Insert a link to a pdf associated with the bibtex entry."
  (let*
      ((entry (bibtex-completion-get-entry key))
       (title (bibtex-completion-get-value "title" entry)))
    (insert (concat "[[file:Download/" key ".pdf][" title "]] (cite:" key ")"))
    )
  )
(defun tdh-insert-link-to-note (key)
  "Insert a link to a note associated with the bibtex entry."
  (if (and bibtex-completion-notes-path
           (f-directory? bibtex-completion-notes-path))
      (let* ((path (f-join bibtex-completion-notes-path
                           (s-concat key bibtex-completion-notes-extension))))
        (if (file-exists-p path)
            (insert (concat "[[file:" (file-relative-name path) "][Notes]]"))
          (message "No note file associated"))
        )))

Open pdf externally

(defun tdh-open-pdf-externally (key)
  (call-process "zathura" nil 0 nil (nth 0 (-cons-to-list (bibtex-completion-find-pdf key)))))

Special Commands

(defun tdh-helm-bibtex-favorites (&optional arg)
  "Search Favorite BibTeX entries"
  (interactive "P")
  (helm-bibtex arg nil "favorite "))

List all element of the bibliography without pdf associated

(defun tdh-list-bib-without-pdf-associated ()
  (interactive)
  (bibtex-completion-init)
  (setq candidates (bibtex-completion-candidates))

  (defun canditate-is-pdf-present (candidate)
    (bibtex-completion-find-pdf-in-library (cdr (assoc "=key=" candidate)))
    )

  (setq candidates-without-pdf (remove-if #'canditate-is-pdf-present candidates))

  (setq candidate-without-pdf-names (mapcar
                                     (lambda (x) (cdr (assoc "title" x)))
                                     candidates-without-pdf))

  (with-output-to-temp-buffer "*bib-without-pdf*" (princ (string-join candidate-without-pdf-names "\n")))
  (switch-to-buffer-other-window "*bib-without-pdf*")
  )

Org-Roam-Bibtex (link)

Provides nice functions such as:

  • orb-find-non-ref-file
  • orb-insert-non-ref
  • orb-note-action
(use-package! org-roam-bibtex
  :after org-roam
  :config
  (setq orb-preformat-keywords '("citekey" "title" "author" "year" "author-abbrev" "entry-type"))
  (setq orb-note-actions-user '(("Open with Zathura" . tdh-open-bib-with-zathura)))
  )
(defun tdh-open-bib-with-zathura (key)
  "Open the pdf corresponding to the reference KEY with Zathura"
  (if (listp key)
      (setq key (car key)))
  (call-process "zathura" nil 0 nil (org-ref-get-pdf-filename key)))

Bibtex-Mode

(after! bibtex
  (map! :map bibtex-mode-map
        :n "C-c c" 'org-ref-clean-bibtex-entry)
  (setq bibtex-files bibtex-completion-bibliography))

Citar

;; (use-package! citar
;;   :custom
;;   (org-cite-global-bibliography '("~/Cloud/brain/biblio/references.bib"))
;;   (setq citar-library-paths '("~/Cloud/pdfs/"))
;;   (setq citar-open-note-function 'orb-citar-edit-note)
;;   (org-cite-insert-processor 'citar)
;;   (org-cite-follow-processor 'citar)
;;   (org-cite-activate-processor 'citar))

LaTeX

Matlab

Setup Matlab Mode

(setq matlab-shell-command "~/.local/bin/matlab")
(setq matlab-shell-command-switches (list "-softwareopengl -nodesktop -nosplash"))
(setq matlab-indent-function t)
(setq mlint-programs '("mlint" "~/.local/bin/mlint"))

Setup Flycheck to work with mlint

(defvar mlint-executable "~/.local/bin/mlint")

(flycheck-define-command-checker 'matlab-mlint
  "A Matlab checker based on mlint."
  :command `(,mlint-executable source)
  :error-patterns
  '((warning line-start "L " line " (C " (1+ digit)  "): " (message) line-end))
  :modes '(matlab-mode))

(add-to-list 'flycheck-checkers 'matlab-mlint)

;; Automatic startup of flycheck for matlab
(add-hook 'matlab-mode-hook 'flycheck-mode)

Completion in the Matlab Shell

;; (map! :map matlab-shell-mode-map
;;       :i "<tab>" 'matlab-shell-c-tab)
(map! :map matlab-shell-mode-map
      :i "<tab>" #'matlab-shell-tab)
(defadvice! inhibit-real-only-a (oldfun &rest r)
  "Temporary remove read-only lines in shell buffer"
  :around#'matlab-shell-collect-command-output
      (let ((inhibit-read-only t)) (apply oldfun r)))

Beautify code

(defun tdh-matlab-beautify-buffer ()
  "Beautify Current Matlab Buffer"
  (interactive)
  ;; First verifies is the current file is a Matlab file
  (if (string= (file-name-extension (buffer-file-name)) "m")
      (progn
        (save-buffer)
        (matlab-shell-run-command (concat "MBeautify.formatFileNoEditor(\"" (buffer-file-name) "\", \"" (buffer-file-name) "\")"))
        (revert-buffer :ignore-auto :noconfirm))
    (message "Current buffer is not a matlab file")
    )
  )

Key Bindings

(defun tdh-matlab-add-breakpoint ()
  (interactive)
  (matlab-shell-run-command (concat "dbstop in " (buffer-name) " at " (number-to-string (line-number-at-pos nil)))))

(defun tdh-matlab-remove-breakpoint ()
  (interactive)
  (matlab-shell-run-command (concat "dbclear in " (buffer-name) " at " (number-to-string (line-number-at-pos nil)))))

(defun tdh-matlab-list-breakpoints ()
  (interactive)
  (matlab-shell-run-command (concat "dbstatus " (buffer-name))))

(defun tdh-matlab-clear-breakpoints ()
  (interactive)
  (matlab-shell-run-command (concat "dbclear in " (buffer-name))))

(defun tdh-matlab-no-debug-on-error ()
  (interactive)
  (matlab-shell-run-command (concat "dbclear if error")))

(defun tdh-matlab-debug-on-error ()
  (interactive)
  (matlab-shell-run-command (concat "dbstop if error")))

(defun tdh-matlab-go-to-file-directory ()
  (interactive)
  (matlab-shell-run-command (concat "cd " (file-name-directory buffer-file-name))))
(map! :map matlab-mode-map
      (:prefix ("," . "prefix")
       :n "g" 'tdh-matlab-go-to-file-directory
       (:prefix ("d" . "Debug")
        :n "de" 'tdh-matlab-debug-on-error
        :n "dE" 'tdh-matlab-no-debug-on-error
        :n "da" 'tdh-matlab-add-breakpoint
        :n "dr" 'tdh-matlab-remove-breakpoint
        :n "dL" 'tdh-matlab-list-breakpoints
        :n "dc" 'tdh-matlab-clear-breakpoints
        :n "dl" 'gud-cont
        :n "ds" 'gud-step
        :n "dn" 'gud-next
        :n "dq" 'gud-finish)))

Useful General Functions

(defun tdh-matlab-work ()
  "Setup Matlab Work Windows"
  (interactive)
  (delete-other-windows)
  (evil-window-vsplit)
  (evil-window-right 1)
  (switch-to-buffer "*MATLAB*")
  (evil-normal-state)
  (evil-goto-line)
  (evil-window-left 1)
  )

Doom init.el

(doom! :completion
       company           ; the ultimate code completion backend
       (corfu +orderless)  ; complete with cap(f), cape and a flying feather!
       helm              ; the *other* search engine for love and life
       ;;ido               ; the other *other* search engine...
       ;;ivy               ; a search engine for love and life
       vertico           ; the search engine of the future

       :ui
       doom              ; what makes DOOM look the way it does
       (emoji +unicode)  ; 🙂
       hl-todo           ; highlight TODO/FIXME/NOTE/DEPRECATED/HACK/REVIEW
       indent-guides     ; highlighted indent columns
       modeline          ; snazzy, Atom-inspired modeline, plus API
       ophints           ; highlight the region an operation acts on
       (popup +defaults)   ; tame sudden yet inevitable temporary windows
       ;;smooth-scroll     ; So smooth you won't believe it's not butter
       unicode           ; extended unicode support for various languages
       (vc-gutter +pretty) ; vcs diff in the fringe
       vi-tilde-fringe   ; fringe tildes to mark beyond EOB
       workspaces        ; tab emulation, persistence & separate workspaces

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

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

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

       :checkers
       syntax              ; tasing you for every semicolon you forget
       (spell +aspell +everywhere) ; tasing you for misspelling mispelling

       :tools
       ;;ansible
       biblio            ; Writes a PhD for you (citation needed)
       ;;collab            ; buffers with friends
       debugger          ; FIXME stepping through code, to help you add bugs
       ;;direnv
       ;;docker
       ;;editorconfig      ; let someone else argue about tabs vs spaces
       ;;ein               ; tame Jupyter notebooks with emacs
       (eval +overlay)     ; run code, run (also, repls)
       (lookup +dictionary)              ; navigate your code and its documentation
       ;;lsp               ; M-x vscode
       magit             ; a git porcelain for Emacs
       ;;make              ; run make tasks from Emacs
       ;;pass              ; password manager for nerds
       pdf               ; pdf enhancements
       ;;terraform         ; infrastructure as code
       ;;tmux              ; an API for interacting with tmux
       ;;tree-sitter       ; syntax and parsing, sitting in a tree...
       ;;upload            ; map local to remote projects via ssh/ftp

       :os
       ;;(:if (featurep :system 'macos) macos)  ; improve compatibility with macOS
       ;;tty               ; improve the terminal Emacs experience

       :lang
       ;;agda              ; types of types of types of types...
       ;;beancount         ; mind the GAAP
       ;;(cc +lsp)         ; C > C++ == 1
       ;;clojure           ; java with a lisp
       ;;common-lisp       ; if you've seen one lisp, you've seen them all
       ;;coq               ; proofs-as-programs
       ;;crystal           ; ruby at the speed of c
       ;;csharp            ; unity, .NET, and mono shenanigans
       data              ; config/data formats
       ;;(dart +flutter)   ; paint ui and not much else
       ;;dhall
       ;;elixir            ; erlang done right
       ;;elm               ; care for a cup of TEA?
       emacs-lisp        ; drown in parentheses
       ;;erlang            ; an elegant language for a more civilized age
       ;;ess               ; emacs speaks statistics
       ;;factor
       ;;faust             ; dsp, but you get to keep your soul
       ;;fortran           ; in FORTRAN, GOD is REAL (unless declared INTEGER)
       ;;fsharp            ; ML stands for Microsoft's Language
       ;;fstar             ; (dependent) types and (monadic) effects and Z3
       ;;gdscript          ; the language you waited for
       ;;(go +lsp)         ; the hipster dialect
       ;;(graphql +lsp)    ; Give queries a REST
       ;;(haskell +lsp)    ; a language that's lazier than I am
       ;;hy                ; readability of scheme w/ speed of python
       ;;idris             ; a language you can depend on
       ;;json              ; At least it ain't XML
       ;;(java +lsp)       ; the poster child for carpal tunnel syndrome
       ;;javascript        ; all(hope(abandon(ye(who(enter(here))))))
       ;;julia             ; a better, faster MATLAB
       ;;kotlin            ; a better, slicker Java(Script)
       latex             ; writing papers in Emacs has never been so fun
       ;;lean              ; for folks with too much to prove
       ;;ledger            ; be audit you can be
       ;;lua               ; one-based indices? one-based indices
       markdown          ; writing docs for people to ignore
       ;;nim               ; python + lisp at the speed of c
       ;;nix               ; I hereby declare "nix geht mehr!"
       ;;ocaml             ; an objective camel
       (org +pretty +roam2 +hugo +noter)               ; organize your plain life in plain text
       ;;php               ; perl's insecure younger brother
       ;;plantuml          ; diagrams for confusing people more
       ;;graphviz          ; diagrams for confusing yourself even more
       ;;purescript        ; javascript, but functional
       python            ; beautiful is better than ugly
       ;;qt                ; the 'cutest' gui framework ever
       ;;racket            ; a DSL for DSLs
       ;;raku              ; the artist formerly known as perl6
       ;;rest              ; Emacs as a REST client
       ;;rst               ; ReST in peace
       ;;(ruby +rails)     ; 1.step {|i| p "Ruby is #{i.even? ? 'love' : 'life'}"}
       ;;(rust +lsp)       ; Fe2O3.unwrap().unwrap().unwrap().unwrap()
       ;;scala             ; java, but good
       ;;(scheme +guile)   ; a fully conniving family of lisps
       sh                ; she sells {ba,z,fi}sh shells on the C xor
       ;;sml
       ;;solidity          ; do you need a blockchain? No.
       ;;swift             ; who asked for emoji variables?
       ;;terra             ; Earth and Moon in alignment for performance.
       ;;web               ; the tubes
       ;;yaml              ; JSON, but readable
       ;;zig               ; C, but simpler

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

       :app
       ;;calendar
       ;;emms
       ;;everywhere        ; *leave* Emacs!? You must be joking
       ;;irc               ; how neckbeards socialize
       ;;(rss +org)        ; emacs as an RSS reader

       :config
       literate
       (default +bindings +smartparens))

Doom packages.el

Org Mode Related

https://github.com/doomemacs/doomemacs/issues/6478

;; Automatic toggling of LaTeX fragments
(package! org-fragtog)
;; Toggle visibility of hidden Org mode element parts upon entering and leaving an element
(package! org-appear)
;; Connector between Org-roam, BibTeX-completion, and Org-ref
(package! org-roam-bibtex
  :recipe (:host github :repo "org-roam/org-roam-bibtex"))
(unpin! org-roam company-org-roam)
;; Org-mode modules for citations, cross-references, bibliographies
(package! org-ref)
;; Org-mode calendar sync
(package! org-caldav)
;; Alert notifications for org-agenda
(package! org-wild-notifier)
;; Turn table into subfigure
(package! ox-latex-subfigure
  :recipe (:host github :repo "tdehaeze/ox-latex-subfigure"))
;; Org-mode query language
(package! org-ql :recipe (:host github :repo "alphapapa/org-ql"
                          :files ("*.el")
                          ))
;; (package! helm-org-ql)

Other

;; Nice theme
(package! poet-theme)
;; Major Mode for Matlab
(package! matlab-mode
  :recipe (:host github :repo "matlab-mode/mirror")
  :pin "f1a709e")
;; Major Mode for Matlab
(package! matlab-mode
  :recipe (:host github :repo "mathworks/Emacs-MATLAB-Mode"))
(package! org-xournalpp
  :recipe (:host gitlab
           :repo "vherrmann/org-xournalpp"
           :files ("resources" "*.el")))