Files
literate-dotfiles/doom.org

3347 lines
118 KiB
Org Mode

#+TITLE: Doom Emacs Configuration
:DRAWER:
#+startup: overview
#+language: en
#+email: dehaeze.thomas@gmail.com
#+author: Dehaeze Thomas
#+html_link_home: ./index.html
#+html_link_up: ./index.html
#+html_head: <link rel="stylesheet" type="text/css" href="./dist/style.css"/>
#+html_head: <script type="text/javascript" src="./dist/script.js"></script>
#+property: header-args:emacs-lisp :tangle ~/.config/doom/config.el :results none :padline no
:END:
* Introduction and Resources
https://medium.com/urbint-engineering/emacs-doom-for-newbies-1f8038604e3b
https://noelwelsh.com/posts/2019-01-10-doom-emacs.html
https://dotdoom.netlify.com/config.html
https://emacs.christianbaeuerlein.com/
https://github.com/nmartin84/.doom.d/blob/master/config.org
https://tecosaur.github.io/emacs-config/config.html#intro
Documentation:
- https://github.com/hlissner/doom-emacs/blob/develop/docs/index.org
When changing =init.el= or =package.el=, tangle the files and then run =doom sync=.
After that, restart Emacs with =spc q r=.
* Useful Bindings
- =align-regexp=: equivalent of [[https://github.com/junegunn/vim-easy-align][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
#+begin_src emacs-lisp
(setq user-full-name "Dehaeze Thomas"
user-mail-address "dehaeze.thomas@gmail.com")
#+end_src
** Doom Config
Fonts
#+begin_src emacs-lisp
(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))
#+end_src
Theme
#+begin_src emacs-lisp
;; (setq doom-theme 'leuven)
(setq doom-theme 'doom-gruvbox-light)
#+end_src
Line numbers
#+begin_src emacs-lisp
(setq display-line-numbers-type t)
#+end_src
Mode Line
#+begin_src emacs-lisp
(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))
#+end_src
** Evil
#+begin_src emacs-lisp
(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
)
#+end_src
Make horizontal movement cross lines
#+begin_src emacs-lisp
(setq-default evil-cross-lines t)
#+end_src
** Which Key
#+begin_src emacs-lisp
(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))
#+end_src
** Visual
Automatic line wrap.
#+begin_src emacs-lisp
(global-visual-line-mode nil)
#+end_src
Turn off auto-fill mode that add line breaks.
#+begin_src emacs-lisp
(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))
#+end_src
** Change default alert backend
#+begin_src emacs-lisp
(setq alert-default-style 'libnotify)
#+end_src
** Spell Check
#+begin_src emacs-lisp
(setq ispell-dictionary "en")
(setq ispell-program-name "aspell")
#+end_src
Correct last work using =C-.=.
#+begin_src emacs-lisp
(defun tdh-correct-last-word ()
(interactive)
(save-excursion
(+spell/previous-error)
(+spell/correct)
)
)
(map! :map org-mode-map
:i "C-." #'tdh-correct-last-word)
#+end_src
Go to previous/next spell mistake using =g[= and =g]=:
#+begin_src emacs-lisp
(map! :map evil-normal-state-map
"g]" #'spell-fu-goto-next-error)
(map! :map evil-normal-state-map
"g[" #'spell-fu-goto-previous-error)
#+end_src
** C-cedilla issue
This tells GTK builds of Emacs to use native input method handling
#+begin_src emacs-lisp
(setq x-gtk-use-system-tooltips nil)
(setq x-gtk-use-native-input t)
#+end_src
** Lockfiles
#+begin_src emacs-lisp
(setq create-lockfiles nil)
#+end_src
** Disable highlight of current line
This helps to speed-up emacs.
#+begin_src emacs-lisp
(global-hl-line-mode -1)
(after! org
(add-hook 'org-mode-hook
(lambda()
(hl-line-mode -1)
(global-hl-line-mode -1))
't
))
#+end_src
** Remap =jump-forward= key binding
#+begin_src emacs-lisp
(with-eval-after-load 'better-jumper
(map!
:desc "Jump Forward"
"C-i" #'better-jumper-jump-forward))
#+end_src
** Magit
#+begin_src emacs-lisp
(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)))
;; )
#+end_src
** 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
#+begin_src emacs-lisp
(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)))
)
#+end_src
** PDF-Tools
Function that opens current pdf page as an SVG file with Inkscape.
#+begin_src emacs-lisp
(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)
))
#+end_src
** Flycheck
Disable flycheck for now with orgmode buffers:
#+begin_src emacs-lisp
(defun disable-flycheck-mode ()
(interactive)
(flycheck-mode -1))
(add-hook 'org-mode-hook 'disable-flycheck-mode)
#+end_src
** Tramp
#+begin_src emacs-lisp
(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'")
)
#+end_src
** Helm AG
Increase the number of "columns" when search for text:
#+begin_src emacs-lisp
(setq counsel-rg-base-command
"rg --max-columns 1000 --with-filename --no-heading --line-number --color never %s")
#+end_src
** Others
#+begin_src emacs-lisp
(setq auto-save-default t)
#+end_src
* Org Mode
- http://cachestocaches.com/2016/9/my-workflow-org-agenda/
- http://doc.norang.ca/org-mode.html#TodoKeywords
- https://emacs.cafe/emacs/orgmode/gtd/2017/06/30/orgmode-gtd.html
** Org General Config
#+begin_src emacs-lisp
(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)
)
#+end_src
TAB was changed to toggle only the visibility state of the current subtree, rather than cycle through it recursively. This can be reversed with:
#+begin_src emacs-lisp
(after! evil-org
(remove-hook 'org-tab-first-hook #'+org-cycle-only-current-subtree-h))
#+end_src
https://github.com/doomemacs/doomemacs/issues/6478#issuecomment-1406167570
#+begin_src emacs-lisp
(after! evil
(setq org-fold-core-style 'overlays)
(evil-select-search-module 'evil-search-module 'evil-search)
)
#+end_src
** Org Inline Images
Display the real size of images and not the one set with =attr_latex: :width \linewidth= for instance.
#+begin_src emacs-lisp
(after! org
(setq org-image-actual-width t))
#+end_src
** Org Links
#+begin_src emacs-lisp
(after! org
(setq org-link-abbrev-alist
'(("bib" . "~/Cloud/brain/biblio/references.bib::%s")
("notes" . "~/Cloud/brain/%s.org")
("papers" . "~/Cloud/pdfs/%s.pdf")))
)
#+end_src
#+begin_src emacs-lisp
(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)
)
#+end_src
** Org Tagging
#+begin_src emacs-lisp
(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))))
)
#+end_src
** Org Refile
#+begin_src emacs-lisp
(after! org
(setq org-refile-targets '((org-agenda-files . (:maxlevel . 6))))
)
#+end_src
** Org TODO
#+begin_src emacs-lisp
(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
)
#+end_src
** Org Archive
https://gist.github.com/Fuco1/e86fb5e0a5bb71ceafccedb5ca22fcfb
Archive subtrees under the same hierarchy as original in the archive files
#+begin_src emacs-lisp
(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))))))))
)
#+end_src
** Org Agenda
General configuration
#+begin_src emacs-lisp
(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"))
)
)
#+end_src
Org Agenda Custom Views
#+begin_src emacs-lisp
(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/")))))
)
)
#+end_src
** Org Structure Template
#+begin_src emacs-lisp
(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")
))
)
#+end_src
** Org Capture
Documentation:
- Template elements: https://orgmode.org/manual/Template-elements.html#Template-elements
- Template expansion: https://orgmode.org/manual/Template-expansion.html#Template-expansion
- Capture protocol: https://orgmode.org/manual/capture-protocol.html
#+begin_src emacs-lisp
(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
)
)))
)
#+end_src
** Org Export
Basic configuration:
#+begin_src emacs-lisp
(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)
)
#+end_src
Some defaults:
#+begin_src emacs-lisp
(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)
)
#+end_src
Do not export headline with the =:ignore:= tag:
#+begin_src emacs-lisp
;; Used to not export headings with :ignore: tag
(after! org
(require 'ox-extra)
(ox-extras-activate '(ignore-headlines)))
#+end_src
** Org-ql
#+begin_src emacs-lisp
(use-package! org-ql
:after org)
#+end_src
** Org Effort
#+begin_src emacs-lisp
(after! org
(setq org-global-properties
'(("Effort_ALL". "0 0:10 0:30 1:00 2:00 3:00 4:00")))
)
#+end_src
** Open Files
#+begin_src emacs-lisp
(after! org
(setq org-file-apps
'((auto-mode . emacs)
("\\.x?html?\\'" . "firefox %s")
("\\.pdf\\'" . "zathura \"%s\"")
("\\.pdf::\\([0-9]+\\)\\'" . "zathura \"%s\" -p %1")))
)
#+end_src
** HTML Export
*** HTML Defaults
#+begin_src emacs-lisp
(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)
)
#+end_src
*** Footnotes
#+begin_src emacs-lisp
(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>"))
#+end_src
*** MathJax
#+begin_src emacs-lisp
(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")))
)
#+end_src
*** MP4 Video - =video= link
#+begin_src emacs-lisp
(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)
)
#+end_src
** Org Xournalpp
#+begin_src emacs-lisp
(use-package! org-xournalpp
:config
(add-hook 'org-mode-hook 'org-xournalpp-mode))
#+end_src
** Org LaTeX
*** LaTeX Fragments
#+begin_src emacs-lisp
(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))
)
#+end_src
From https://karthinks.com/software/scaling-latex-previews-in-emacs/, scale the LaTeX fragments with the text:
#+begin_src emacs-lisp
(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)
)
#+end_src
*** LaTeX Classes
#+begin_src emacs-lisp
(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}"))
)
)
#+end_src
*** Ox Latex Subfigure package
#+begin_src emacs-lisp
(use-package! ox-latex-subfigure
:load-path "~/.config/doom/packages/ox-latex-subfigure/"
:config (require 'ox-latex-subfigure))
#+end_src
*** Clear page before heading
https://emacs.stackexchange.com/questions/30575/adding-latex-newpage-before-a-heading/30892
#+begin_src emacs-lisp
(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)
)
#+end_src
*** TODO Default added packages
#+begin_src emacs-lisp
(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
)
)
#+end_src
#+begin_src emacs-lisp
(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))
)
#+end_src
*** Some configurations
#+begin_src emacs-lisp
(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))
)
#+end_src
*** Beamer
Bold Text
#+begin_src emacs-lisp
(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)
)
#+end_src
Special Environments
- [ ] Make some comment those special environments
#+begin_src emacs-lisp
(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}"
"}"))
)
#+end_src
*** Number Equations
https://kitchingroup.cheme.cmu.edu/blog/2016/11/07/Better-equation-numbering-in-LaTeX-fragments-in-org-mode/
#+begin_src emacs-lisp
(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)
)
#+end_src
** 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/
#+begin_src emacs-lisp
(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"))
)
#+end_src
** Automatically run =startblock= when opening org-mode files
#+begin_src emacs-lisp
(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)
)
#+end_src
** Org mode and Yasnippet
=TAB= used not to work well with Yasnippet ([[https://github.com/doomemacs/doomemacs/issues/7733#issuecomment-2586904927][github issue]]), with the following, it works well:
#+begin_src emacs-lisp
(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)
#+end_src
** Some function
#+begin_src emacs-lisp
(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))))
#+end_src
** Render Tables
https://www.reddit.com/r/emacs/comments/d3a8or/pretty_org_tables_in_the_buffer_chapter_2_it/
#+begin_src emacs-lisp :tangle no
(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)))
)
#+end_src
** Disable LaTeX fragments in table
#+begin_src emacs-lisp
(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)
#+end_src
** Org CalDAV
#+begin_src emacs-lisp
(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"
))
#+end_src
** Org Inline Task
#+begin_src emacs-lisp
(after! org
(require 'org-inlinetask)
)
#+end_src
** Org Links
*** =yt:= Youtube Links
#+begin_src emacs-lisp
(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"))))))
)
#+end_src
*** =message:= link to mutt
#+begin_src emacs-lisp
;; 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
#+end_src
** Org Wild Notifier
#+begin_src emacs-lisp
(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)
)
#+end_src
** Custom Keybindings - =,= leader key and =C-c=
| | |
|---------+-------------------|
| =C-c a= | Org Agenda |
| =C-c n= | Narrow to Subtree |
| =C-c l= | Org Link |
#+begin_src emacs-lisp
(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)
))
#+end_src
*** Insert Elements =,i=
Insert Link to paper
#+begin_src emacs-lisp
(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))))
#+end_src
Insert Link to notes
#+begin_src emacs-lisp
(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))))
#+end_src
Insert Image that is in the figs folder
#+begin_src emacs-lisp
(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)))
#+end_src
Insert Image that is in the =figs= folder using SXIV
#+begin_src emacs-lisp
(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)))
)
#+end_src
Copy picture from phone folder using SXIV and insert it
#+begin_src emacs-lisp
(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)))
)
#+end_src
Bash script for copying pictures taken by phone.
#+begin_src bash :comments both :mkdirp yes :shebang "#!/usr/bin/env bash" :tangle ~/.config/doom/bin/copy-phone-picture.sh
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
#+end_src
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
#+begin_src emacs-lisp
(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)
)
#+end_src
Insert link to next figure:
#+begin_src emacs-lisp
(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)))
)
#+end_src
Insert link to previous figure:
#+begin_src emacs-lisp
(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)))
)
#+end_src
Insert link to next table:
#+begin_src emacs-lisp
(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)))
)
#+end_src
Insert link to previous table:
#+begin_src emacs-lisp
(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)))
)
#+end_src
Map Keys
#+begin_src emacs-lisp
(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)))
#+end_src
*** LaTeX =,l=
#+begin_src emacs-lisp
(defun tdh-latex-watch ()
"Watch LaTeX file using latexmk"
(interactive)
(start-process-shell-command "latexmk-watch" "*latexmk-watch-output*"
"latexmk -bibtex -pvc"))
#+end_src
#+begin_src emacs-lisp
(defun tdh-latex-watch-kill ()
"Kill the currently running TeX job."
(interactive)
(delete-process "latexmk-watch")
)
#+end_src
#+begin_src emacs-lisp
(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)))
#+end_src
*** Org LaTeX Automatic fragment
#+begin_src emacs-lisp
(use-package! org-fragtog
:after org
:config
(add-hook 'org-mode-hook 'org-fragtog-mode)
)
#+end_src
#+begin_src emacs-lisp
(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))
#+end_src
#+begin_src emacs-lisp
(after! org
(map! :map org-mode-map
(:prefix (",l" . "LaTeX")
:n "f" 'tdh-automatic-latex-fragment-activate
:n "F" 'tdh-automatic-latex-fragment-deactivate)))
#+end_src
*** Org-Appear
#+begin_src emacs-lisp
(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 ))
#+end_src
*** Bibtex =,r=
#+begin_src emacs-lisp
(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)))
#+end_src
*** Open yazi in current directory =,o=
#+begin_src emacs-lisp
(defun tdh-open-yazi-in-workdir ()
(interactive)
(call-process-shell-command
(concat "kitty -e yazi " default-directory) nil 0))
#+end_src
#+begin_src emacs-lisp
(after! org
(map! :map org-mode-map
:n ",o" 'tdh-open-yazi-in-workdir))
#+end_src
*** View in External programs =,v=
Open PDF output with =zathura=
#+begin_src emacs-lisp
(defun tdh-open-org-pdf-externally ()
(interactive)
(call-process "zathura" nil 0 nil (concat (file-name-sans-extension (buffer-file-name)) ".pdf"))
)
#+end_src
Open HTML output externally
#+begin_src emacs-lisp
(defun tdh-open-org-html-externally ()
(interactive)
(call-process "xdg-open" nil 0 nil (concat (file-name-sans-extension (buffer-file-name)) ".html"))
)
#+end_src
#+begin_src emacs-lisp
(after! org
(map! :map org-mode-map
(:prefix (",v" . "View")
:n "p" 'tdh-open-org-pdf-externally
:n "h" 'tdh-open-org-html-externally)))
#+end_src
* Org Babel
** Main configuration
Don't ask for confirmation when evaluating following blocs
#+begin_src emacs-lisp
(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))
#+end_src
Default header arguments.
#+begin_src emacs-lisp
(after! org
(setq org-babel-default-header-args '((:eval . "no-export"))))
#+end_src
Use the current window for C-c ' source editing
#+begin_src emacs-lisp
(after! org
(setq org-src-window-setup 'current-window))
#+end_src
** Appearance of source blocks
#+begin_src emacs-lisp
(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)
#+end_src
** Indentation
#+begin_src emacs-lisp
(after! org
;; Don't change indentation when toggling
(setq org-src-preserve-indentation t)
)
#+end_src
** Library of Babel
Add all named source blocks to =org-babel-library-of-babel= ([[file:emacs-library-babel.org][link]]).
#+begin_src emacs-lisp
(after! org
(org-babel-lob-ingest "~/.config/literate-dotfiles/emacs-library-babel.org"))
#+end_src
** Org-Babel Matlab
#+begin_src emacs-lisp
(after! org
(setq org-babel-matlab-shell-command "~/.local/bin/matlab -softwareopengl -nodesktop -nosplash")
)
#+end_src
Default options for Matlab code
#+begin_src emacs-lisp
(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")))
)
#+end_src
Better format the output results for Matlab ([[https://www.reddit.com/r/emacs/comments/fy98bs/orgbabels_matlab_session_output_is_malformed/?utm_source=share&utm_medium=web2x][link]]).
#+begin_src emacs-lisp
(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)))))
)
#+end_src
** Some functions for using Matlab with Org Babel =,m=
=whos= matlab function
#+begin_src emacs-lisp
(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"))))
#+end_src
=help= matlab function
#+begin_src emacs-lisp
(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")))
)
#+end_src
Specify a Matlab command to run
#+begin_src emacs-lisp
(defun tdh-matlab-run-command ()
"Prompt user to enter a matlab command"
(interactive)
(process-send-string "*MATLAB*" (concat (read-string "Matlab Command: ") "\n")))
#+end_src
Specify a Matlab command to run and show output in mini-buffer
#+begin_src emacs-lisp
(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")))
#+end_src
Org-Babel Tangle File and Execute with Matlab
#+begin_src emacs-lisp
(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)))))
#+end_src
Map Functions
#+begin_src emacs-lisp
(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)))
#+end_src
** 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=.
#+begin_src emacs-lisp
(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)))
#+end_src
#+begin_src emacs-lisp
(map! :after evil-org
:map evil-org-mode-map
:n "<C-return>" #'tdh-ctrl-ret)
#+end_src
** 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=
#+begin_src emacs-lisp
(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))
)))
)
)
#+end_src
*** =tdh-matlab-execute-selected=
#+begin_src emacs-lisp
(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"))))
#+end_src
*** 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
#+begin_src emacs-lisp
(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)
)
)
#+end_src
#+begin_src emacs-lisp
(map! :after evil-org
:map evil-org-mode-map
:n "<C-S-return>" #'tdh-ctrl-shift-ret)
#+end_src
** Align Source Blocks
#+begin_src emacs-lisp
(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)))
#+end_src
** Helping Functions - Tangling =,b=
Org-Babel Tangle Sub-tree
#+begin_src emacs-lisp
(defun tdh-org-babel-tangle-subtree ()
"Tangle the current subtree"
(interactive)
(progn
(org-narrow-to-subtree)
(org-babel-tangle)
(widen))
)
#+end_src
Org-Tangle and Org-Babel Jump to Tangle File
#+begin_src emacs-lisp
(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)))))
#+end_src
#+begin_src emacs-lisp
(defun tdh-org-babel-tangle-block ()
(interactive)
(let ((current-prefix-arg '(4)))
(call-interactively 'org-babel-tangle)
))
#+end_src
Map Functions
#+begin_src emacs-lisp
(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)))
#+end_src
* 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 ([[https://github.com/jkitchin/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=
#+begin_src emacs-lisp
(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")))))
)
#+end_src
#+begin_src emacs-lisp
(after! org
(require 'org-ref))
#+end_src
#+begin_src emacs-lisp
(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)
#+end_src
#+begin_src emacs-lisp
(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))))))
)
#+end_src
** Org Noter ([[https://github.com/weirdNox/org-noter][link]])
#+begin_src emacs-lisp
(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))
)
#+end_src
** Capture Templates
*** Bibliography
#+begin_src org :tangle ~/.config/doom/capture-templates/ref.org :mkdirp yes
- 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
#+end_src
*** Default
#+begin_src org :tangle ~/.config/doom/capture-templates/default.org
- Tags ::
%?
,* Bibliography
bibliography:./biblio/references.bib
#+end_src
** Org Roam ([[https://github.com/jethrokuan/org-roam/][link]])
#+begin_src emacs-lisp
(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)))
)
#+end_src
Automatic export of backlinks
#+begin_src emacs-lisp
(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)
)
#+end_src
Correctly export references for Hugo blog.
#+begin_src emacs-lisp
(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)
)
#+end_src
Re-Export all roam files.
#+begin_src emacs-lisp
(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)))))
#+end_src
** Helm-Bibtex ([[https://github.com/tmalsburg/helm-bibtex][link]])
#+begin_src emacs-lisp
(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)
)
#+end_src
#+begin_src emacs-lisp
(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 ")"))
)
)
#+end_src
#+begin_src emacs-lisp
(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"))
)))
#+end_src
Open pdf externally
#+begin_src emacs-lisp
(defun tdh-open-pdf-externally (key)
(call-process "zathura" nil 0 nil (nth 0 (-cons-to-list (bibtex-completion-find-pdf key)))))
#+end_src
Special Commands
#+begin_src emacs-lisp
(defun tdh-helm-bibtex-favorites (&optional arg)
"Search Favorite BibTeX entries"
(interactive "P")
(helm-bibtex arg nil "favorite "))
#+end_src
List all element of the bibliography without pdf associated
#+begin_src emacs-lisp
(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*")
)
#+end_src
** Org-Roam-Bibtex ([[https://github.com/org-roam/org-roam-bibtex][link]])
Provides nice functions such as:
- =orb-find-non-ref-file=
- =orb-insert-non-ref=
- =orb-note-action=
#+begin_src emacs-lisp
(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)))
)
#+end_src
#+begin_src emacs-lisp
(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)))
#+end_src
** Bibtex-Mode
#+begin_src emacs-lisp
(after! bibtex
(map! :map bibtex-mode-map
:n "C-c c" 'org-ref-clean-bibtex-entry)
(setq bibtex-files bibtex-completion-bibliography))
#+end_src
** Citar
#+begin_src emacs-lisp
;; (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))
#+end_src
* LaTeX
- https://tex.stackexchange.com/questions/52179/what-is-your-favorite-emacs-and-or-auctex-command-trick
- https://tex.stackexchange.com/questions/20843/useful-shortcuts-or-key-bindings-or-predefined-commands-for-emacsauctex
** Basic Config
#+begin_src emacs-lisp
(after! auctex
(setq +latex-viewers '(zathura pdf-tools)))
#+end_src
** Bibtex
#+begin_src emacs-lisp
(use-package! bibtex
:config
(bibtex-set-dialect 'BibTeX))
#+end_src
* Matlab
- https://sourceforge.net/projects/matlab-emacs/
** Setup Matlab Mode
#+begin_src emacs-lisp
(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"))
#+end_src
** Setup Flycheck to work with =mlint=
#+begin_src emacs-lisp
(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)
#+end_src
** Completion in the Matlab Shell
#+begin_src emacs-lisp
;; (map! :map matlab-shell-mode-map
;; :i "<tab>" 'matlab-shell-c-tab)
(map! :map matlab-shell-mode-map
:i "<tab>" #'matlab-shell-tab)
#+end_src
#+begin_src emacs-lisp
(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)))
#+end_src
** Beautify code
#+begin_src emacs-lisp
(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")
)
)
#+end_src
** Key Bindings
#+begin_src emacs-lisp
(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))))
#+end_src
#+begin_src emacs-lisp
(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)))
#+end_src
** Useful General Functions
#+begin_src emacs-lisp
(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)
)
#+end_src
* Doom =init.el=
#+begin_src emacs-lisp :tangle ~/.config/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))
#+end_src
* Doom =packages.el=
:PROPERTIES:
:header-args:emacs-lisp: :tangle ~/.config/doom/packages.el
:END:
** Org Mode Related
https://github.com/doomemacs/doomemacs/issues/6478
#+begin_src emacs-lisp
;; Automatic toggling of LaTeX fragments
(package! org-fragtog)
#+end_src
#+begin_src emacs-lisp
;; Toggle visibility of hidden Org mode element parts upon entering and leaving an element
(package! org-appear)
#+end_src
#+begin_src emacs-lisp
;; 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)
#+end_src
#+begin_src emacs-lisp
;; Org-mode modules for citations, cross-references, bibliographies
(package! org-ref)
#+end_src
#+begin_src emacs-lisp
;; Org-mode calendar sync
(package! org-caldav)
#+end_src
#+begin_src emacs-lisp
;; Alert notifications for org-agenda
(package! org-wild-notifier)
#+end_src
#+begin_src emacs-lisp
;; Turn table into subfigure
(package! ox-latex-subfigure
:recipe (:host github :repo "tdehaeze/ox-latex-subfigure"))
#+end_src
#+begin_src emacs-lisp
;; Org-mode query language
(package! org-ql :recipe (:host github :repo "alphapapa/org-ql"
:files ("*.el")
))
;; (package! helm-org-ql)
#+end_src
** Other
#+begin_src emacs-lisp
;; Nice theme
(package! poet-theme)
#+end_src
#+begin_src emacs-lisp :tangle no
;; Major Mode for Matlab
(package! matlab-mode
:recipe (:host github :repo "matlab-mode/mirror")
:pin "f1a709e")
#+end_src
#+begin_src emacs-lisp
;; Major Mode for Matlab
(package! matlab-mode
:recipe (:host github :repo "mathworks/Emacs-MATLAB-Mode"))
#+end_src
#+begin_src emacs-lisp
(package! org-xournalpp
:recipe (:host gitlab
:repo "vherrmann/org-xournalpp"
:files ("resources" "*.el")))
#+end_src
** Not used anymore :noexport:
:PROPERTIES:
:header-args:emacs-lisp: :tangle no
:END:
#+begin_src emacs-lisp
;; Web Server
(package! web-server)
#+end_src
#+begin_src emacs-lisp
(package! mpv)
#+end_src
#+begin_src emacs-lisp
(package! pretty-hydra)
#+end_src
#+begin_src emacs-lisp
;; custom blocks and links for org-mode
(package! org-special-block-extras)
#+end_src
#+begin_src emacs-lisp
;; Import file to Org-mode
(package! org-pandoc-import
:recipe (:host github
:repo "tecosaur/org-pandoc-import"
:files ("*.el" "filters" "preprocessors")))
#+end_src
#+begin_src emacs-lisp
(package! org-media-note
:recipe (:host github :repo "yuchen-lea/org-media-note"))
#+end_src
#+begin_src emacs-lisp
(package! igo-org
:recipe (:host github
:repo "misohena/el-igo"
:branch "master"
:files ("*.el")))
#+end_src
#+begin_src emacs-lisp
(package! org-transclusion
:recipe (:host github
:repo "nobiot/org-transclusion"
:branch "main"
:files ("*.el")))
#+end_src
Why this was pinned?
#+begin_src emacs-lisp
;; (package! org-mode :pin "971eb6885ec996c923e955730df3bafbdc244e54")
#+end_src
#+begin_src emacs-lisp
;; Nice theme
(package! languagetool)
#+end_src
#+begin_src emacs-lisp
;; Don't use this default package in Doom
(package! evil-escape :disable t)
#+end_src
#+begin_src emacs-lisp
;; Nice gantt charts
(package! ob-mermaid)
#+end_src
#+begin_src emacs-lisp
;; Vimrc
(package! vimrc-mode)
(package! transient :pin "c2bdf7e12c530eb85476d3aef317eb2941ab9440")
(package! with-editor :pin "391e76a256aeec6b9e4cbd733088f30c677d965b")
#+end_src
#+begin_src emacs-lisp
(package! org-ai)
#+end_src