literate-dotfiles/doom.org

3522 lines
124 KiB
Org Mode
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#+title: Doom Emacs Configuration
#+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
* Installation
#+begin_src bash :tangle no
yay -Ss aspell aspell-fr aspell-en
#+end_src
* 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
;; These are used for a number of things, particularly for GPG configuration,
;; some email clients, file templates and snippets.
(setq user-full-name "Dehaeze Thomas"
user-mail-address "dehaeze.thomas@gmail.com")
#+end_src
** Doom Config
#+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
#+begin_src emacs-lisp
(setq doom-theme 'leuven)
#+end_src
#+begin_src emacs-lisp
(setq display-line-numbers-type t)
#+end_src
#+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))
#+end_src
Make movement keys work like they should
#+begin_src emacs-lisp
(define-key evil-normal-state-map (kbd "<remap> <evil-next-line>") 'evil-next-visual-line)
(define-key evil-normal-state-map (kbd "<remap> <evil-previous-line>") 'evil-previous-visual-line)
(define-key evil-motion-state-map (kbd "<remap> <evil-next-line>") 'evil-next-visual-line)
(define-key evil-motion-state-map (kbd "<remap> <evil-previous-line>") 'evil-previous-visual-line)
#+end_src
Make horizontal movement cross lines
#+begin_src emacs-lisp
(setq-default evil-cross-lines t)
#+end_src
;; In org-mode, $ does not go to the real end of line, it jumps to the end of /visual/ line
;; Create a real end of line by APPENDING and then going back to normal state
Evil Surround (not working):
#+begin_src emacs-lisp :tangle no
;; this macro was copied from here: https://stackoverflow.com/a/22418983/4921402
(defmacro define-and-bind-quoted-text-object (name key start-regex end-regex)
(let ((inner-name (make-symbol (concat "evil-inner-" name)))
(outer-name (make-symbol (concat "evil-a-" name))))
`(progn
(evil-define-text-object ,inner-name (count &optional beg end type)
(evil-select-paren ,start-regex ,end-regex beg end type count nil))
(evil-define-text-object ,outer-name (count &optional beg end type)
(evil-select-paren ,start-regex ,end-regex beg end type count t))
(define-key evil-inner-text-objects-map ,key #',inner-name)
(define-key evil-outer-text-objects-map ,key #',outer-name))))
;; Add dollar as a surround object
(define-and-bind-quoted-text-object "dollar" "$" "\\$" "\\$")
#+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
** 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
** Change default alert backend
#+begin_src emacs-lisp
(setq alert-default-style 'libnotify)
#+end_src
** Spell Check
Switch from one language to an other ([[https://stackoverflow.com/questions/42159012/emacs-spell-check-on-fly-for-2-languages][link]]).
#+begin_src emacs-lisp
(setq ispell-dictionary "en_US")
(setq ispell-program-name "aspell")
#+end_src
#+begin_src emacs-lisp
(defun tdh-correct-last-word ()
(interactive)
(save-excursion
(+spell/previous-error)
(+spell/correct)
)
)
#+end_src
#+begin_src emacs-lisp
(define-key evil-insert-state-map (kbd "C-l") 'tdh-correct-last-word)
#+end_src
** Lockfiles
#+begin_src emacs-lisp
(setq create-lockfiles nil)
#+end_src
** Disable highlight of current line
#+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-repository-directories `(("~/Cloud/thesis/matlab/" . 1)
("~/Cloud/thesis/papers/" . 1)))
(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
#+begin_src emacs-lisp
(use-package! pdf-tools
:config
(add-hook 'pdf-view-mode-hook (lambda() (linum-mode -1)))
)
#+end_src
#+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))
#+end_src
#+begin_src emacs-lisp
(after! pdf-tools
(map! :map pdf-view-mode-map
(:desc "Screenshot"
:ni "C-c s" 'tdh-screenshot-page)
))
#+end_src
** Flycheck
#+begin_src emacs-lisp :tangle no
(flycheck-define-checker proselint
"A linter for prose."
:command ("proselint" source-inplace)
:error-patterns
((warning line-start (file-name) ":" line ":" column ": "
(id (one-or-more (not (any " "))))
(message (one-or-more not-newline)
(zero-or-more "\n" (any " ") (one-or-more not-newline)))
line-end))
:modes (text-mode markdown-mode gfm-mode org-mode))
(add-to-list 'flycheck-checkers 'proselint)
#+end_src
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
** Yassnippets
#+begin_src emacs-lisp
(push "~/.config/doom/snippets" yas-snippet-dirs)
(yas-global-mode 1)
#+end_src
** Ox-Hugo
#+begin_src emacs-lisp
(defun tdh-export-everything-to-hugo ()
"Export all the .org files in the specified directory to markdown using Hugo"
(interactive)
(setq org-files (directory-files (read-directory-name "Directory:" "/home/thomas/Cloud/brain/") t "org$" t))
(while org-files
(setq current-org-file (car org-files))
(message "Exporting %s" current-org-file)
(find-file current-org-file)
(org-hugo-export-to-md)
(setq org-files (cdr org-files))))
#+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)
;; 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)
)
#+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
** 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)" "NEXT(n)" "MAIL(m)" "|" "DONE(d)")
(sequence "READ(r)" "BKMK(b)" "EXER(x)" "|" "DONE(d)")
(sequence "WAIT(w@/!)" "SDAY(s)" "|" "CANC(c@/!)")
(sequence "QUES(q)" "|" "ANSW(a)")
(sequence "EXAM(e)" "IDEA(i)" "|")
))
;; Display of the keywords
(setq org-todo-keyword-faces
'(("TODO" . (:foreground "#cc241d" :weight bold)) ;; red
("EXER" . (:foreground "#cc241d" :weight bold)) ;; red
("NEXT" . (: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
("WAIT" . (:foreground "#d65d0e" :weight bold)) ;; orange
("QUES" . (:foreground "#d79921" :weight bold)) ;; yellow
("CANC" . (:foreground "#a89984" :weight bold)) ;; grey
("SDAY" . (:foreground "#98971a" :weight bold)) ;; green
("BKMK" . (:foreground "#98971a" :weight bold)) ;; green
("IDEA" . (:foreground "#98971a" :weight bold)) ;; green
("EXAM" . (: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]+>"))
(setq org-agenda-custom-commands
'(("w" "Work"
((org-ql-block '(and (tags "@work")
(todo "TODO")
(priority "A"))
((org-ql-block-header "Important TODOs")))
(org-ql-block '(and (tags "@work")
(todo "TODO")
(priority "B"))
((org-ql-block-header "TODOs")))
(org-ql-block '(and (tags "@work")
(todo "TODO")
(priority "C"))
((org-ql-block-header "Not important TODOs")))))
("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
** TODO Org Agenda HTML
This function can be used to export the week calendar to html.
This html page can be used as a starting page for the browser.
This idea comes from [[https://blog.lambda.cx/posts/org-agenda-new-tab/][here]].
#+begin_src emacs-lisp :tangle no
(defun tdh-org-agenda-to-html ()
(interactive)
(org-agenda-list)
(org-agenda-write "/ssh:thomas@homelab:~/docker/config/calendar/www/index.html"))
#+end_src
** Org Fancy Priority
#+begin_src emacs-lisp
(use-package! org-fancy-priorities ; priority icons
:hook (org-mode . org-fancy-priorities-mode)
:config (setq org-fancy-priorities-list '("" "" "")))
#+end_src
** Org Notification based on calendar event
https://emacs.stackexchange.com/questions/3844/good-methods-for-setting-up-alarms-audio-visual-triggered-by-org-mode-events
#+begin_src emacs-lisp
(after! org-agenda
(setq appt-message-warning-time 5)
(defun tdh-org-agenda-to-appt ()
(interactive)
(setq appt-time-msg-list nil)
(org-agenda-to-appt))
(tdh-org-agenda-to-appt)
; Display appointments as a window manager notification
(setq appt-disp-window-function 'tdh-appt-display)
(setq appt-delete-window-function (lambda () t))
(setq tdh-appt-notification-app (concat (getenv "HOME") "/bin/appt-notification"))
(defun tdh-appt-display (min-to-app new-time msg)
(if (atom min-to-app)
(start-process "tdh-appt-notification-app" nil tdh-appt-notification-app min-to-app msg)
(dolist (i (number-sequence 0 (1- (length min-to-app))))
(start-process "tdh-appt-notification-app" nil tdh-appt-notification-app (nth i min-to-app) (nth i msg)))))
)
#+end_src
*** appt-notification script
#+begin_src bash :tangle ~/.config/doom/bin/appt-notification :shebang "#!/usr/bin/env bash" :comments none :mkdirp yes
TIME="$1"TODO
MSG="$2"
dunstify --replace=85401 "Event in $TIME minutes" "$MSG"
#+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-notebook.org" "Inbox") ; target
"** TODO %?\n%U\n" ; template
)
("M" ; key
"Meeting" ; name
entry ; type
(file+headline "~/Cloud/org/work-notebook.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-notebook.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-notebook.org" "Mails")
"* MAIL %: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-notebook.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-notebook.org" "Inbox")
"* [[%:link][%:description]]\nCaptured On: %U\n\n"
:immediate-finish t
)
("pt"
"Org-Protocol text"
entry
(file+headline "~/Cloud/org/work-notebook.org" "Inbox")
"* %:description\nSource: %:link\nCaptured On: %U\n\n#+begin_quote\n%i\n#+end_quote\n\n"
:immediate-finish t
)
)))
)
#+end_src
** =message:= link to mutt
#+begin_src emacs-lisp
(require 'org-protocol)
(defun stefanv/mutt-open-message (message-id)
"In neomutt, open the email with the the given Message-ID"
(let*
((message-id (replace-regexp-in-string "^/*" "" message-id))
(mail-file
(replace-regexp-in-string
"\n$" "" (shell-command-to-string
(format "mu find -f l i:%s | head -n 1" message-id))))
(mail-dir (replace-regexp-in-string "/\\(cur\\|new\\|tmp\\)/$" ""
(file-name-directory mail-file)))
(process-id (concat "neomutt-" message-id))
(message-id-escaped (regexp-quote message-id))
(mutt-keystrokes
(format "L~i %s\n\nLall\n\nl" (shell-quote-argument message-id-escaped)))
(mutt-command (list "neomutt" "-R" "-f" mail-dir
"-e" (format "push '%s'" mutt-keystrokes))))
(message "Launching neomutt for message %s" message-id)
(call-process "setsid" nil nil
"-f" "alacritty" "-e"
"neomutt" "-R" "-f" mail-dir
"-e" (format "push '%s'" mutt-keystrokes))))
; Whenever org-mode sees a link starting with `message://`, it
; calls our `mutt-open-message` function
(org-add-link-type "message" 'stefanv/mutt-open-message)
#+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")
)
#+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 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
** 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: %SCALE,
fontCache: \"global\"
},
tex: {
tags: \"%AUTONUMBER\",
multlineWidth: \"%MULTLINEWIDTH\",
tagSide: \"%TAGSIDE\",
macros: {bm: [\"\\\\boldsymbol{#1}\",1],},
tagIndent: \"%TAGINDENT\"
}
};
</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
*** TODO Ensuring useful HTML Anchors
- [ ] https://github.com/alhassy/emacs.d
- [ ] https://github.com/alphapapa/unpackaged.el#export-to-html-with-useful-anchors
This is not working
#+begin_src emacs-lisp :tangle no
(define-minor-mode unpackaged/org-export-html-with-useful-ids-mode
"Attempt to export Org as HTML with useful link IDs.
Instead of random IDs like \"#orga1b2c3\", use heading titles,
made unique when necessary."
:global t
(if unpackaged/org-export-html-with-useful-ids-mode
(advice-add #'org-export-get-reference :override #'unpackaged/org-export-get-reference)
(advice-remove #'org-export-get-reference #'unpackaged/org-export-get-reference)))
(defun unpackaged/org-export-get-reference (datum info)
"Like `org-export-get-reference', except uses heading titles instead of random numbers."
(let ((cache (plist-get info :internal-references)))
(or (car (rassq datum cache))
(let* ((crossrefs (plist-get info :crossrefs))
(cells (org-export-search-cells datum))
;; Preserve any pre-existing association between
;; a search cell and a reference, i.e., when some
;; previously published document referenced a location
;; within current file (see
;; `org-publish-resolve-external-link').
;;
;; However, there is no guarantee that search cells are
;; unique, e.g., there might be duplicate custom ID or
;; two headings with the same title in the file.
;;
;; As a consequence, before re-using any reference to
;; an element or object, we check that it doesn't refer
;; to a previous element or object.
(new (or (cl-some
(lambda (cell)
(let ((stored (cdr (assoc cell crossrefs))))
(when stored
(let ((old (org-export-format-reference stored)))
(and (not (assoc old cache)) stored)))))
cells)
(when (org-element-property :raw-value datum)
;; Heading with a title
(unpackaged/org-export-new-named-reference datum cache))
(when (member (car datum) '(src-block table example fixed-width property-drawer))
;; Nameable elements
(unpackaged/org-export-new-named-reference datum cache))
;; NOTE: This probably breaks some Org Export
;; feature, but if it does what I need, fine.
(org-export-format-reference
(org-export-new-reference cache))))
(reference-string new))
;; Cache contains both data already associated to
;; a reference and in-use internal references, so as to make
;; unique references.
(dolist (cell cells) (push (cons cell new) cache))
;; Retain a direct association between reference string and
;; DATUM since (1) not every object or element can be given
;; a search cell (2) it permits quick lookup.
(push (cons reference-string datum) cache)
(plist-put info :internal-references cache)
reference-string))))
(defun unpackaged/org-export-new-named-reference (datum cache)
"Return new reference for DATUM that is unique in CACHE."
(cl-macrolet ((inc-suffixf (place)
`(progn
(string-match (rx bos
(minimal-match (group (1+ anything)))
(optional "--" (group (1+ digit)))
eos)
,place)
;; HACK: `s1' instead of a gensym.
(-let* (((s1 suffix) (list (match-string 1 ,place)
(match-string 2 ,place)))
(suffix (if suffix
(string-to-number suffix)
0)))
(setf ,place (format "%s--%s" s1 (cl-incf suffix)))))))
(let* ((headline-p (eq (car datum) 'headline))
(title (if headline-p
(org-element-property :raw-value datum)
(or (org-element-property :name datum)
(concat (org-element-property :raw-value
(org-element-property :parent
(org-element-property :parent datum)))))))
;; get ascii-only form of title without needing percent-encoding
(ref (concat (org-reference-contraction (substring-no-properties title))
(unless (or headline-p (org-element-property :name datum))
(concat ","
(pcase (car datum)
('src-block "code")
('example "example")
('fixed-width "mono")
('property-drawer "properties")
(_ (symbol-name (car datum))))
"--1"))))
(parent (when headline-p (org-element-property :parent datum))))
(while (--any (equal ref (car it))
cache)
;; Title not unique: make it so.
(if parent
;; Append ancestor title.
(setf title (concat (org-element-property :raw-value parent)
"--" title)
;; get ascii-only form of title without needing percent-encoding
ref (org-reference-contraction (substring-no-properties title))
parent (when headline-p (org-element-property :parent parent)))
;; No more ancestors: add and increment a number.
(inc-suffixf ref)))
ref)))
(add-hook 'org-load-hook #'unpackaged/org-export-html-with-useful-ids-mode)
#+end_src
*** TODO Folded Drawers
Adapt this from https://github.com/alhassy/emacs.d to do something similar for source blocks.
#+begin_src emacs-lisp :tangle no
(defun my/org-drawer-format (name contents)
"Export to HTML the drawers named with prefix fold_, ignoring case.
The resulting drawer is a code-details and so appears folded;
the user clicks it to see the information therein.
Henceforth, these are called fold drawers.
Drawers without such a prefix may be nonetheless exported if their
body contains :export: t ---this switch does not appear in the output.
Thus, we are biased to generally not exporting non-fold drawers.
One may suspend export of fold drawers by having :export: nil
in their body definition.
Fold drawers naturally come with a title.
Either it is specfied in the drawer body by :title: ⋯’,
or otherwise the drawer's name is used with all underscores replaced
by spaces.
"
(let* ((contents (replace-regexp-in-string ":export:.*\n?" "" contents))
(fold? (s-prefix? "fold_" name 'ignore-case))
(export? (string-match ":export:\s+t" contents))
(not-export? (string-match ":export:\s+nil" contents))
(title (and (string-match ":title:\\(.*\\)\n" contents)
(match-string 1 contents))))
;; Ensure we have a title.
(unless title (setq title (s-join " " (cdr (s-split "_" name)))))
;; Output
(cond
((and export? (not fold?)) contents)
(not-export? nil)
(fold?
(thread-last contents
(replace-regexp-in-string ":title:.*\n" "")
(format "<details class=\"code-details\"> <summary> <strong>
<font face=\"Courier\" size=\"3\" color=\"green\"> %s
</font> </strong> </summary> %s </details>" title))))))
(setq org-html-format-drawer-function 'my/org-drawer-format)
#+end_src
** Org Xournalpp
#+begin_src emacs-lisp
(use-package! org-xournalpp
:config
(add-hook 'org-mode-hook 'org-xournalpp-mode))
#+end_src
#+begin_src emacs-lisp :tangle no
(setq org-xournalpp-template-getter (lambda () "/home/thomas/Downloads/template_test.xopp"))
#+end_src
** Org Transclusion
#+begin_src emacs-lisp
(use-package! org-transclusion
:config
)
#+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 "~/.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 ("xetex" "dvisvgm")
:description "xdv > svg"
:message "you need to install the programs: xetex and dvisvgm."
:image-input-type "xdv"
:image-output-type "svg"
:image-size-adjust (0.6 . 0.6)
:latex-compiler ("xelatex -no-pdf -output-directory %o %f")
:image-converter ("dvisvgm %f -n -b min -c %S -o %O"))
))
;; Use imagemagick/dvisvgm to generate png from pdf
(setq org-preview-latex-default-process 'pdf2svg)
;; 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
(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
*** 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
;; :after org
;; :config (require 'ox-latex-subfigure))
#+end_src
#+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 -bibtex -f %f"))
)
#+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
(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
*** TODO Custom Export - Add Page and Label for LaTeX export
https://emacs.stackexchange.com/questions/156/emacs-function-to-convert-an-arbitrary-org-property-into-an-arbitrary-string-na?rq=1
#+begin_src emacs-lisp :tangle no
(defcustom tdh-org-property-mapping
'((latex ("CUSTOM_PAGE" . tdh-insert-org-page-latex)
("CUSTOM_LABEL" . tdh-insert-org-label-latex)))
"List of mappings from org property to arbitrary strings.
Each element is a list:
(BACKEND (PROPERTY1 . FUNCTION1) (PROPERTY2 . FUNCTION2) ...)
FUNCTION are functions which get called with a single
argument (the value of PROPERTY) and are responsible for doing
whatever should be done."
:type '(repeat (cons symbol (repeat (cons string string)))))
#+end_src
#+begin_src emacs-lisp :tangle no
(defun tdh-replace-org-property (backend)
"Convert org properties using `tdh-org-property-mapping'.
Lookup BACKEND in `tdh-org-property-mapping' for a list of
(PROPERTY REPLACEMENT). For each healine being exported, if it has a
PROPERTY listed insert a string immediately after the healine given by
(format REPLACEMENT PROPERTY-VALUE)"
(let ((map (cdr (assoc backend tdh-org-property-mapping)))
value replacement)
(when map
(org-map-entries
(lambda ()
(dolist (it map)
(save-excursion
(when (setq value (org-entry-get (point) (car it)))
(funcall (cdr it) value)))))))))
(add-hook 'org-export-before-processing-hook #'tdh-replace-org-property)
#+end_src
#+begin_src emacs-lisp :tangle no
(defun tdh-insert-org-label-latex (label)
"Insert \"\\\\label{LABEL}\\n\" after the :PROPERTY: drawer."
(search-forward-regexp org-property-end-re)
(forward-char 1)
(insert (format "\\label{%s}\n" label)))
(defun tdh-insert-org-page-latex (page)
"Insert \"\\\\page{PAGE}\\n\" after the :PROPERTY: drawer."
(search-forward-regexp org-property-end-re)
(forward-char 1)
(insert (format "\\page{%s}\n" page)))
#+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
** Org Media Note
#+begin_src emacs-lisp :tangle no
(use-package! org-media-note
:hook (org-mode . org-media-note-setup-org-ref)
:bind (
("H-v" . org-media-note-hydra/body)) ;; Main entrance
:config
(setq org-media-note-screenshot-image-dir "~/Pictures/") ;; Folder to save screencast
(setq org-media-note-use-refcite-first t) ;; use videocite link instead of video link if possible
)
#+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
** Org Projects
#+begin_src emacs-lisp
(setq org-publish-project-alist
'(("config"
:base-directory "~/.config/literate-dotfiles/"
:publishing-directory "~/.config/literate-dotfiles/docs/"
:recursive nil
:publishing-function org-html-publish-to-html
:auto-sitemap nil
:section-numbers nil
:table-of-contents nil)
("stewart-simscape"
:base-directory "~/Cloud/thesis/matlab/stewart-simscape/org/"
:base-extension "org"
:publishing-directory "~/Cloud/thesis/matlab/stewart-simscape/docs/"
:author "Dehaeze Thomas"
:email "dehaeze.thomas@gmail.com/"
:recursive nil
:publishing-function org-html-publish-to-html
:auto-preamble t
:auto-sitemap nil
:html-link-up "index.html"
:html-link-home "index.html"
:with-todo-keywords nil
:html-wrap-src-lines nil
:table-of-contents nil)
("nass-simscape"
:base-directory "~/Cloud/thesis/matlab/nass-simscape/org/"
:base-extension "org"
:publishing-directory "~/Cloud/thesis/matlab/nass-simscape/docs/"
:author "Dehaeze Thomas"
:email "dehaeze.thomas@gmail.com/"
:recursive nil
:publishing-function (list org-html-publish-to-html org-latex-publish-to-pdf)
:auto-preamble t
:auto-sitemap nil
:html-link-up "index.html"
:html-link-home "index.html"
:with-todo-keywords nil
:html-wrap-src-lines nil
:table-of-contents nil)
("tikz-maker"
:base-directory "~/Cloud/tikz/org/"
:base-extension "org"
:publishing-directory "~/Cloud/tikz/docs/"
:author "Dehaeze Thomas"
:email "dehaeze.thomas@gmail.com/"
:recursive nil
:publishing-function org-html-publish-to-html
:auto-preamble t
:auto-sitemap nil
:html-link-up "index.html"
:html-link-home "index.html"
:with-todo-keywords nil
:html-wrap-src-lines nil
:table-of-contents nil)))
#+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
** 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
** TODO Insert ScreenShot or Picture from Phone
http://pragmaticemacs.com/emacs/a-workflow-to-quickly-add-photos-to-org-mode-notes/
- [ ] One function to move file from =~/Picture/= folder (where the screenshots are taken) to current directory and then insert and org link to the picture. Maybe ask if it should be copied in a sub directory (figs folder for instance).
- [ ] One function to copy file from =~/Cloud/Photos/= folder (where the pictures from phone are taken) to current directory (and ask for the new name of the picture) and insert org link.
#+begin_src emacs-lisp :tangle no
;; required libraries
(require 'dash)
;; (require 'swiper)
(require 's)
;; start directory
(defvar tdh-image-dir (expand-file-name "/home/thomas/Pictures"))
(defun tdh-insert-conference-image ()
"Insert image from conference directory, rename and add link in current file.
The file is taken from a start directory set by `tdh-image-dir' and moved to the current directory, renamed and embedded at the point as an org-mode link. The user is presented with a list of files in the start directory, from which to select the file to move, sorted by most recent first."
(interactive)
(let (file-list target-dir file-list-sorted start-file start-file-full file-ext end-file end-file-base end-file-full file-number)
;; Clean directories from list but keep times
(setq file-list
(-remove (lambda (x) (nth 1 x))
(directory-files-and-attributes tdh-image-dir)))
;; Get target directory
(setq target-dir (file-name-directory (buffer-file-name)))
;; Sort list by most recent
(setq file-list-sorted
(mapcar #'car
(sort file-list
#'(lambda (x y) (time-less-p (nth 6 y) (nth 6 x))))))
;; Use ivy to select start-file
(setq start-file (ivy-read
(concat "Move selected file to " target-dir ":")
file-list-sorted
:re-builder #'ivy--regex
:sort nil
:initial-input nil))
;; add full path to start file and end-file
(setq start-file-full
(expand-file-name start-file tdh-image-dir))
;; final file name including path
(setq end-file-full
(expand-file-name start-file target-dir))
;; rename file
(rename-file start-file-full end-file-full)
(message "moved %s to %s" start-file-full start-file)
;; insert link
(insert (org-make-link-string (format "file:%s" start-file)))
;; display image
(org-display-inline-images t t)))
#+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
(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
** Org Special Block Extras
#+begin_src emacs-lisp
(after! org
(require 'org-special-block-extras)
)
#+end_src
** Org Inline Task
#+begin_src emacs-lisp
(after! org
(require 'org-inlinetask)
)
#+end_src
** Org Links
*** 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
** Citeproc-Org
#+begin_src emacs-lisp
(use-package! citeproc-org
:after ox-hugo
:config
(citeproc-org-setup))
#+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
** TODO Orch
#+begin_src emacs-lisp :tangle no
(use-package! web-server
:init
:config
)
#+end_src
#+begin_src emacs-lisp :tangle no
(add-to-list 'load-path "~/.config/doom/packages/orch/")
(autoload 'orch-toggle "orch" nil t)
#+end_src
** TODO [#A] 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 "Insert Screenshot"
:ni "C-c s" 'tdh-insert-screenshot-org-link)
(:desc "Find Roam"
:ni "C-c r" 'orb-find-non-ref-file)
(:desc "Insert Roam"
:ni "C-c R" 'orb-insert-non-ref)
))
#+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 | sxiv -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 | sxiv -i -t -o | tail -1);
else
oldpath=$(ls -t $1 | sxiv -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 "[[" (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 "[[" (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" "-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
*** 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 ranger in current directory =,o=
#+begin_src emacs-lisp
(defun tdh-open-ranger-in-workdir ()
(interactive)
(call-process-shell-command
(concat "alacritty -e ranger " default-directory) nil 0))
#+end_src
#+begin_src emacs-lisp
(after! org
(map! :map org-mode-map
:n ",o" 'tdh-open-ranger-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"))))
(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 "/home/thomas/.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
(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
** Mermaid
#+begin_src bash :tangle no
yay -S mermaid-cli
#+end_src
#+begin_src emacs-lisp
(use-package! ob-mermaid
:after org
:config
(setq ob-mermaid-cli-path "/usr/bin/mmdc")
)
#+end_src
#+begin_src mermaid :file figs/mermaid.png :theme default :background-color transparent :tangle no :exports both
gantt
dateFormat YYYY-MM-DD
title Adding GANTT diagram to mermaid
excludes weekdays 2014-01-10
section A section
Completed task :done, des1, 2014-01-06,2014-01-08
Active task :active, des2, 2014-01-09, 3d
Future task : des3, after des2, 5d
Future task2 : des4, after des3, 5d
#+end_src
#+RESULTS:
[[file:figs/mermaid.png]]
** 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)))
(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
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 "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
:init
:config
;; Folder where the notes files are located (or file if just one Note file)
(setq org-ref-notes-directory "~/Cloud/brain")
(setq org-ref-bibliography-notes "~/Cloud/brain")
;; Bibliography File
(setq reftex-default-bibliography '("~/Cloud/brain/biblio/references.bib"))
(setq org-ref-default-bibliography '("~/Cloud/brain/biblio/references.bib"))
;; Folder where all the pdf are located
(setq org-ref-pdf-directory "~/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)
(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-drag-and-drop "
(file-name-as-directory org-ref-pdf-directory)
(car (org-ref-get-bibtex-key-and-file))
".pdf"))))
t)
;; Let Mathjax deals with equation reference
(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))))
)
#+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
** 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
- Tags :: %?
- Reference :: ${ref}
- Author(s) :: %^{author}
- Year :: %^{year}
,* %^{author-abbrev} (%^{year}): %^{title} :%^{entry-type}:ignore:
:PROPERTIES:
:NOTER_DOCUMENT: ../pdfs/%^{citekey}.pdf
:END:
,* Bibliography :ignore:
,#+BIBLIOGRAPHY: here
#+end_src
*** Default
#+begin_src org :tangle ~/.config/doom/capture-templates/default.org
- Tags ::
%?
,* Bibliography :ignore:
,#+BIBLIOGRAPHY: here
#+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 :tangle no
(after! (org org-roam)
(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
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-all-files))
(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"
"~/Cloud/acoustic/resources/acoustics.bib"))
;; Directory with all the pdfs
(setq bibtex-completion-library-path '("~/Cloud/pdfs/"
"~/Cloud/acoustic/resources/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 "")
;; 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
** Deft ([[https://github.com/jrblevin/deft][link]])
#+begin_src emacs-lisp :tangle no
(use-package! deft
:custom
(deft-directory "~/Cloud/brain/"))
#+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
** Citeproc-org ([[https://github.com/andras-simonyi/citeproc-org][link]])
#+begin_src emacs-lisp
(use-package! citeproc-org
:after org
:config
(citeproc-org-setup)
(setq citeproc-org-html-backends '(html)))
#+end_src
** Bibtex-Mode
#+begin_src emacs-lisp
(after! bibtex
(map! :map bibtex-mode-map
:n "C-c c" 'org-ref-clean-bibtex-entry))
#+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 "/home/thomas/.local/bin/matlab")
(setq matlab-shell-command-switches (list "-softwareopengl -nodesktop -nosplash"))
(setq matlab-indent-function t)
(setq mlint-programs '("mlint" "/home/thomas/.local/bin/mlint"))
#+end_src
** Setup Flycheck to work with =mlint=
#+begin_src emacs-lisp
(defvar mlint-executable "/home/thomas/.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-tab)
#+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
* Pandoc
#+begin_src emacs-lisp :tangle no
(use-package! pandoc-mode
)
#+end_src
* Mu4e
** Resources
Documentation:
- [ ] Mu4e documentation: http://www.djcbsoftware.nl/code/mu/mu4e/index.html#Top
- [ ] https://github.com/djcb/mu
Use contexts for multiple accounts:
- [ ] https://vxlabs.com/2017/02/07/mu4e-0-9-18-e-mailing-with-emacs-now-even-better/
- [ ] http://cachestocaches.com/2017/3/complete-guide-email-emacs-using-mu-and-/
- [ ] https://notanumber.io/2016-10-03/better-email-with-mu4e/
Send math and source code:
- [ ] https://vxlabs.com/2015/01/28/sending-emails-with-math-and-source-code/
** Cheatsheet
| Command | Usage |
|---------+-----------------------|
| =C-j= | Next mail |
| =C-k= | Previous mail |
| =R/C/F= | Reply/Compose/Forward |
| =t= | Move to Archive |
| =d= | Move to Trash |
** Helping function
This is a helper to help determine which account context I am in based on the folder in my maildir the email (eg. ~/.mail/nine27) is located in.
#+begin_src emacs-lisp
(defun mu4e-message-maildir-matches (msg rx)
(when rx
(if (listp rx)
;; If rx is a list, try each one for a match
(or (mu4e-message-maildir-matches msg (car rx))
(mu4e-message-maildir-matches msg (cdr rx)))
;; Not a list, check rx
(string-match rx (mu4e-message-field msg :maildir)))))
#+end_src
Choose account label to feed msmtp -a option based on From header in Message buffer; This function must be added to message-send-mail-hook for on-the-fly change of From address before sending message since message-send-mail-hook is processed right before sending message.
#+begin_src emacs-lisp
(defun choose-msmtp-account ()
(if (message-mail-p)
(save-excursion
(let*
((from (save-restriction
(message-narrow-to-headers)
(message-fetch-field "from")))
(account
(cond
((string-match "dehaeze.thomas@gmail.com" from) "gmail")
((string-match "thomas.dehaeze@esrf.fr" from) "esrf"))))
(setq message-sendmail-extra-arguments (list '"-a" account))))))
#+end_src
** Basic Config
#+begin_src emacs-lisp
(use-package! mu4e
:config
(setq mail-user-agent 'mu4e-user-agent
mu4e-mu-binary "/usr/bin/mu"
mu4e-maildir "~/.mail"
mu4e-compose-format-flowed t
mu4e-compose-in-new-frame nil
mu4e-view-show-images t
mu4e-html2text-command "w3m -dump -T text/html"
mu4e-use-fancy-chars t
mu4e-headers-include-related t
mu4e-attachment-dir "~/Downloads"
message-kill-buffer-on-exit t
mu4e-compose-signature-auto-include t
mu4e-view-show-images t
mu4e-view-show-addresses t)
)
#+end_src
** Additional config
#+begin_src emacs-lisp
(use-package! mu4e
:config
;; Use imagemagick, if available.
(when (fboundp 'imagemagick-register-types)
(imagemagick-register-types))
;; Sometimes html email is just not readable in a text based client, this lets me open the
;; email in my browser.
(add-to-list 'mu4e-view-actions '("View in browser" . mu4e-action-view-in-browser) t)
;; Spell checking ftw.
(add-hook 'mu4e-compose-mode-hook 'flyspell-mode)
;; Use Helm to select mailboxes
(setq mu4e-completing-read-function 'completing-read)
;; Don't ask for a 'context' upon opening mu4e
(setq mu4e-context-policy 'pick-first)
;; Don't ask to quit... why is this the default?
(setq mu4e-confirm-quit nil)
)
#+end_src
** Provide Information
#+begin_src emacs-lisp
(use-package! mu4e
:config
(setq mu4e-user-mail-address-list '("dehaeze.thomas@gmail.com" "thomas.dehaeze@esrf.fr")
mu4e-compose-signature "Thomas Dehaeze\n"
user-mail-address "dehaeze.thomas@gmail.com")
;; Default Folders
(setq mu4e-sent-folder "/gmail/Sent"
mu4e-drafts-folder "/gmail/Drafts"
mu4e-trash-folder "/gmail/Trash"
mu4e-refile-folder "/gmail/Archive")
)
#+end_src
** Receiving emails using mbsync
#+begin_src emacs-lisp
(use-package! mu4e
:config
(setq mu4e-get-mail-command "checkmail"
mu4e-update-interval nil
mu4e-change-filenames-when-moving t) ;; Fix for mbsync
)
#+end_src
** Contexts
#+begin_src emacs-lisp
(use-package! mu4e
:config
(setq mu4e-contexts
`( ,(make-mu4e-context
:name "gmail"
:enter-func (lambda () (mu4e-message "Switch to the gmail context"))
:match-func (lambda (msg) (when msg
(string-prefix-p "/gmail" (mu4e-message-field msg :maildir))))
:leave-func (lambda () (mu4e-clear-caches))
:vars '(
(user-mail-address . "dehaeze.thomas@gmail.com")
(user-full-name . "Thomas Dehaeze")
(mu4e-sent-folder . "/gmail/Sent")
(mu4e-trash-folder . "/gmail/Trash")
(mu4e-drafts-folder . "/gmail/Drafts")
(mu4e-refile-folder . "/gmail/Archive")
(mu4e-compose-signature . "Thomas Dehaeze\n")
))
,(make-mu4e-context
:name "esrf"
:enter-func (lambda () (mu4e-message "Switch to the esrf context"))
:match-func (lambda (msg) (when msg
(string-prefix-p "/esrf" (mu4e-message-field msg :maildir))))
:leave-func (lambda () (mu4e-clear-caches))
:vars '(
(user-mail-address . "thomas.dehaeze@esrf.fr")
(user-full-name . "Thomas Dehaeze")
(mu4e-sent-folder . "/esrf/Sent")
(mu4e-trash-folder . "/esrf/Trash")
(mu4e-drafts-folder . "/esrf/Drafts")
(mu4e-refile-folder . "/esrf/Archive")
(mu4e-compose-signature . "Thomas Dehaeze\n")
))
))
)
#+end_src
** Sending mails
#+begin_src emacs-lisp
(use-package! mu4e
:config
(setq message-send-mail-function 'message-send-mail-with-sendmail
sendmail-program "/usr/bin/msmtp"
user-full-name "Thomas Dehaeze")
;; This prevents saving the email to the Sent folder since gmail will do this for us on their end.
(setq mu4e-sent-messages-behavior 'delete)
;; Use the correct account context when sending mail based on the from header.
(setq message-sendmail-envelope-from 'header)
(add-hook 'message-send-mail-hook 'choose-msmtp-account)
)
#+end_src
** Bookmarks
#+begin_src emacs-lisp
(use-package! mu4e
:config
(setq mu4e-bookmarks `(,(make-mu4e-bookmark
:name "All Inboxes"
:query "maildir:/gmail/Inbox OR maildir:/esrf/Inbox"
:key ?i)
("flag:unread" "Unread messages" ?u)
("date:today..now" "Today's messages" ?t)
("date:7d..now" "Last 7 days" ?w)))
)
#+end_src
* Doom =init.el=
#+begin_src emacs-lisp :tangle ~/.config/doom/init.el
(when noninteractive
(after! undo-tree
(global-undo-tree-mode -1)))
(doom! :completion
company ; the ultimate code completion backend
helm ; the *other* search engine for love and life
ivy ; a search engine for love and life
:ui
doom ; what makes DOOM look the way it does
deft
hl-todo ; highlight TODO/FIXME/NOTE/DEPRECATED/HACK/REVIEW
hydra
modeline
ophints ; highlight the region an operation acts on
(popup ; tame sudden yet inevitable temporary windows
+all ; catch all popups that start with an asterix
+defaults) ; default popup rules
unicode ; extended unicode support for various languages
vc-gutter ; vcs diff in the fringe
vi-tilde-fringe ; fringe tildes to mark beyond EOB
workspaces ; tab emulation, persistence & separate workspaces
(emoji +unicode)
:editor
(evil +everywhere); come to the dark side, we have cookies
fold ; (nigh) universal code folding
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 +icons) ; making dired pretty [functional]
electric ; smarter, keyword-based electric-indent
(ibuffer +icons) ; interactive buffer management
vc ; version-control and Emacs, sitting in a tree
undo
:term
eshell ; a consistent, cross-platform shell (WIP)
vterm
:tools
debugger ; Stepping through code, to help you add bugs
(eval +overlay) ; run code, run (also, repls)
(lookup ; helps you navigate your code and documentation
+docsets) ; ...or in Dash docsets locally
lsp
magit ; a git porcelain for Emacs
docker
;;pass ; password manager for nerds
pdf ; pdf enhancements
eval
biblio
(lookup +dictionary)
:checkers
syntax ; tasing you for every semicolon you forget
(spell +aspell) ; tasing you for misspelling mispelling
:lang
data ; config/data formats
emacs-lisp ; drown in parentheses
go
(javascript
+lsp)
(latex
+latexmk)
;; markdown ; writing docs for people to ignore
(org ; organize your plain life in plain text
+dragndrop ; drag & drop files/images into org buffers
+hugo ; use Emacs for hugo blogging
+roam2 ;
+gnuplot
+present) ; using org-mode for presentations
python ; beautiful is better than ugly
(sh ; she sells {ba,z,fi}sh shells on the C xor
+lsp)
(web
+lsp)
yaml
:email
(mu4e +gmail)
:app
;; calendar
;;(rss +org) ; emacs as an RSS reader
;;write ; emacs for writers (fiction, notes, papers, etc.)
:config
literate
(default +bindings)
)
#+end_src
* Doom =packages.el=
:PROPERTIES:
:header-args:emacs-lisp: :tangle ~/.config/doom/packages.el
:END:
#+begin_src emacs-lisp
(package! org-xournalpp
:recipe (:host gitlab
:repo "vherrmann/org-xournalpp"
:files ("resources" "*.el")))
#+end_src
#+begin_src emacs-lisp
(package! org-transclusion
:recipe (:host github
:repo "nobiot/org-transclusion"
:branch "main"
:files ("*.el")))
#+end_src
#+begin_src emacs-lisp
;; Vimrc
(package! vimrc-mode)
#+end_src
#+begin_src emacs-lisp
(package! org-media-note
:recipe (:host github :repo "yuchen-lea/org-media-note"))
(package! mpv)
(package! pretty-hydra)
#+end_src
#+begin_src emacs-lisp
;; Automatic toggling of LaTeX fragments
(package! org-fragtog)
#+end_src
#+begin_src emacs-lisp
;; custom blocks and links for org-mode
(package! org-special-block-extras)
#+end_src
#+begin_src emacs-lisp
;; Nice theme
(package! poet-theme)
#+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
;; Renders Org-mode citations in CSL styles
(package! citeproc-org)
#+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
;; 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 "linktohack/ox-latex-subfigure"))
#+end_src
#+begin_src emacs-lisp
;; Major Mode for Matlab
(package! matlab-mode
:recipe (:host github :repo "matlab-mode/mirror"))
#+end_src
#+begin_src emacs-lisp
;; Org-mode query language
(package! org-ql)
(package! helm-org-ql)
#+end_src
#+begin_src emacs-lisp
;; Display Org Mode priorities as custom strings
(package! org-fancy-priorities)
#+end_src
#+begin_src emacs-lisp :tangle no
;; Web Server
(package! web-server)
#+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