3095 lines
115 KiB
Org Mode
3095 lines
115 KiB
Org Mode
#+TITLE: Doom Emacs Configuration
|
||
:DRAWER:
|
||
#+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="./css/htmlize.css"/>
|
||
#+HTML_HEAD: <link rel="stylesheet" type="text/css" href="./css/readtheorg.css"/>
|
||
#+HTML_HEAD: <script type="text/javascript" src="./js/jquery.min.js"></script>
|
||
#+HTML_HEAD: <script type="text/javascript" src="./js/bootstrap.min.js"></script>
|
||
#+HTML_HEAD: <script type="text/javascript" src="./js/jquery.stickytableheaders.min.js"></script>
|
||
#+HTML_HEAD: <script type="text/javascript" src="./js/readtheorg.js"></script>
|
||
|
||
#+PROPERTY: header-args :tangle ~/.config/doom/config.el :results none :padline no
|
||
:END:
|
||
|
||
* Introduction and Resources :ignore:
|
||
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
|
||
|
||
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 |
|
||
|
||
** 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 'doom-gruvbox)
|
||
#+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))
|
||
#+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
|
||
|
||
** 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-window-left 1)
|
||
)
|
||
#+end_src
|
||
|
||
** Change default alert backend
|
||
#+begin_src emacs-lisp
|
||
(setq alert-default-style 'libnotify)
|
||
#+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
|
||
(use-package! dired-narrow
|
||
:config
|
||
(map! :map dired-mode-map
|
||
:n "f"
|
||
'dired-narrow-fuzzy))
|
||
#+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
|
||
|
||
** 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
|
||
|
||
* 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
|
||
|
||
** 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)
|
||
|
||
(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
|
||
|
||
** 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
|
||
:PROPERTIES:
|
||
:header-args: :tangle ~/.config/doom/bin/appt-notification
|
||
:header-args+: :comments none :mkdirp yes
|
||
:header-args+: :shebang "#!/usr/bin/env bash"
|
||
:END:
|
||
#+begin_src bash
|
||
TIME="$1"TODO
|
||
MSG="$2"
|
||
|
||
dunstify --replace=85401 "Event in $TIME minutes" "$MSG"
|
||
#+end_src
|
||
|
||
** Org Structure Template
|
||
#+begin_src emacs-lisp
|
||
(after! org
|
||
(setq org-structure-template-alist
|
||
'(("c" . "center")
|
||
("C" . "comment")
|
||
("m" . "src matlab\n")
|
||
("l" . "src emacs-lisp\n")
|
||
("i" . "important")
|
||
("e" . "example")
|
||
("q" . "quote")
|
||
("s" . "src")))
|
||
)
|
||
#+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\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
|
||
|
||
** 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
|
||
|
||
** HTML Export
|
||
*** HTML Defaults
|
||
#+begin_src emacs-lisp
|
||
(after! org
|
||
;; (setq org-html-head-extra (concat
|
||
;; "<link rel='stylesheet' href='../css/htmlize.css'>\n"
|
||
;; "<link rel='stylesheet' href='../css/readtheorg.css'>\n"
|
||
;; "<link rel='stylesheet' href='../css/zenburn.css'>\n"
|
||
;; "<link rel='text/javascript' href='../js/bootstrap.min.js'>\n"
|
||
;; "<link rel='text/javascript' href='../js/jquery.min.js'>\n"
|
||
;; "<link rel='text/javascript' href='../js/jquery.stickytableheaders.min.js'>\n"
|
||
;; "<link rel='text/javascript' href='../js/readtheorg.js'>\n"))
|
||
|
||
;; cleans up anything that would have been in there.
|
||
(setq org-html-head nil)
|
||
(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
|
||
|
||
*** MathJax
|
||
#+begin_src emacs-lisp
|
||
(after! org
|
||
(setq org-html-mathjax-template
|
||
"<script>MathJax = {
|
||
tex: {
|
||
tags: 'ams',
|
||
macros: {bm: [\"\\\\boldsymbol{#1}\",1],}
|
||
}
|
||
};
|
||
</script>
|
||
<script type=\"text/javascript\" src=\"%PATH\"></script>")
|
||
|
||
(setq org-html-mathjax-options
|
||
'((path "https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js")
|
||
(scale "100")
|
||
(align "center")
|
||
(font "TeX")
|
||
(linebreaks "false")
|
||
(autonumber "AMS")
|
||
(indent "0em")
|
||
(multlinewidth "85%")
|
||
(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))))
|
||
|
||
(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-title-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-title-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* ((title (org-element-property :raw-value datum))
|
||
(ref (url-hexify-string (substring-no-properties title)))
|
||
(parent (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)
|
||
ref (url-hexify-string (substring-no-properties title))
|
||
parent (org-element-property :parent parent))
|
||
;; No more ancestors: add and increment a number.
|
||
(inc-suffixf ref)))
|
||
ref)))
|
||
#+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 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 %D -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"))
|
||
(dvisvgm
|
||
:programs ("pdflatex" "dvisvgm")
|
||
:description "dvi > svg"
|
||
:message "you need to install the programs: latex and dvisvgm."
|
||
:image-input-type "dvi"
|
||
:image-output-type "svg"
|
||
:image-size-adjust (0.6 . 0.6)
|
||
:latex-compiler ("latex -interaction nonstopmode -output-directory %o %f")
|
||
:image-converter ("dvisvgm %f -n -b min -c %S -o %O"))
|
||
))
|
||
|
||
;; Use imagemagick/dvisvgm to generate png from pdf
|
||
(setq org-preview-latex-default-process 'dvisvgm)
|
||
|
||
;; Don't change the font size for subscripts and superscripts in latex fragments.
|
||
;; This cause the orgmode tables not to be well aligned.
|
||
(setq font-latex-fontify-script nil)
|
||
|
||
;; Colors of latex fragments
|
||
(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{scrreprt}"
|
||
("\\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
|
||
|
||
*** Default added packages
|
||
#+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 "\\linewidth")
|
||
(setq org-latex-image-default-height "")
|
||
(setq org-latex-image-default-option "")
|
||
|
||
;; 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
|
||
|
||
** 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 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)
|
||
("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
|
||
|
||
** 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 Links
|
||
*** Youtube Links
|
||
#+begin_src emacs-lisp
|
||
(setq yt-iframe-format
|
||
;; You may want to change your width and height.
|
||
(concat "<iframe width=\"1280\""
|
||
" height=\"720\""
|
||
" src=\"https://www.youtube.com/embed/%s\""
|
||
" frameborder=\"0\""
|
||
" allowfullscreen>%s</iframe>"))
|
||
|
||
(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}"
|
||
path (or desc "video"))))))
|
||
#+end_src
|
||
|
||
** Org Gcal
|
||
- https://cestlaz.github.io/posts/using-emacs-26-gcal/#.WIqBud9vGAk
|
||
|
||
#+begin_src emacs-lisp
|
||
(use-package! org-gcal
|
||
:after org
|
||
:init
|
||
:config
|
||
(setq org-gcal-client-id "396102378658-dcmbcmrnthbe925519otsjbd921otq0v.apps.googleusercontent.com"
|
||
org-gcal-client-secret "4M5PWrbhQjwYEMXGK85lDYX9"
|
||
org-gcal-file-alist '(("dehaeze.thomas@gmail.com" . "~/Cloud/org/gcal.org")
|
||
("8kjmhe2ar0abnm054ill1fb0gc@group.calendar.google.com" . "~/Cloud/org/gcal_phd.org")))
|
||
;; Automatic fetch of the new events
|
||
;; (add-hook 'org-agenda-mode-hook (lambda () (org-gcal-fetch) ))
|
||
)
|
||
#+end_src
|
||
|
||
** Citeproc-Org
|
||
#+BEGIN_SRC emacs-lisp
|
||
(use-package! citeproc-org
|
||
:ensure t
|
||
: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
|
||
)
|
||
#+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 -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" (format "-pdflatex=\"xelatex -synctex=1 -shell-escape -interaction nonstopmode -output-directory='%s'\" -pdf -pvc -bibtex -f %s.tex"
|
||
(file-name-directory buffer-file-name)
|
||
(file-name-base buffer-file-name))))
|
||
#+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
|
||
(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 "termite --directory=" default-directory " --exec=ranger") 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
|
||
(setq org-edit-src-content-indentation 2
|
||
org-src-tab-acts-natively nil
|
||
org-src-preserve-indentation nil)
|
||
)
|
||
#+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
|
||
|
||
** 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)))
|
||
(tdh-ctrl-ret))
|
||
)
|
||
)
|
||
)
|
||
#+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)
|
||
(evil-indent (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))))
|
||
#+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
|
||
|
||
** 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 "~/Cloud/brain/")
|
||
(setq org-roam-completion-system 'helm)
|
||
(setq org-roam-tag-sources '(prop last-directory))
|
||
(setq org-roam-capture-templates
|
||
`(("d" "default" plain (function org-roam--capture-get-point)
|
||
"%?"
|
||
:file-name "${slug}"
|
||
:head ,(concat "#+TITLE: ${title}\n"
|
||
"#+SETUPFILE: ./setup/org-setup-file.org\n"
|
||
"#+HUGO_SECTION: zettels\n"
|
||
"\n"
|
||
"- Tags ::\n"
|
||
"\n"
|
||
"* Bibliography :ignore:\n"
|
||
"bibliography:./biblio/references.bib"
|
||
)
|
||
:unnarrowed t)))
|
||
(setq org-roam-capture-ref-templates
|
||
`(("r" "ref" plain (function org-roam--capture-get-point)
|
||
"%?"
|
||
:file-name "${slug}"
|
||
:head ,(concat "#+TITLE: ${title}\n"
|
||
"#+SETUPFILE: ./setup/org-setup-file.org\n"
|
||
"#+HUGO_SECTION: websites\n"
|
||
"#+ROAM_KEY: ${ref}\n"
|
||
"\n"
|
||
"- Tags ::\n"
|
||
)
|
||
:unnarrowed t)))
|
||
)
|
||
#+end_src
|
||
|
||
Automatic export of backlinks
|
||
#+begin_src emacs-lisp
|
||
(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)
|
||
|
||
|
||
(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")
|
||
|
||
;; Directory with all the pdfs
|
||
(setq bibtex-completion-library-path "~/Cloud/pdfs/")
|
||
|
||
;; Directory with notes files
|
||
(setq bibtex-completion-notes-path "~/Cloud/brain/")
|
||
|
||
(setq bibtex-completion-notes-extension ".org")
|
||
|
||
(setq bibtex-completion-pdf-extension '(".pdf" ".djvu"))
|
||
|
||
;; Use "tags" field when looking for bib entries
|
||
(setq helm-bibtex-additional-search-fields '(tags))
|
||
|
||
(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"
|
||
"\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
|
||
#+begin_src emacs-lisp
|
||
(use-package! deft
|
||
:custom
|
||
(deft-directory "~/Cloud/brain/"))
|
||
#+end_src
|
||
|
||
** Org-Roam-Bibtex ([[https://github.com/Zaeph/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
|
||
:hook (org-roam-mode . org-roam-bibtex-mode)
|
||
:config
|
||
(setq orb-preformat-keywords `("=key=" "title" "author" "year" "author-abbrev" "=type="))
|
||
|
||
(setq orb-templates
|
||
`(("r" "ref" plain (function org-roam-capture--get-point) ""
|
||
:file-name "${=key=}"
|
||
:head ,(concat "#+TITLE: ${title}\n"
|
||
"#+SETUPFILE: ./setup/org-setup-file.org\n"
|
||
"#+HUGO_SECTION: ${=type=}\n"
|
||
"#+ROAM_KEY: ${ref}\n"
|
||
"\n"
|
||
"- Tags ::\n"
|
||
"- Reference :: ${ref}\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"
|
||
)
|
||
:unnarrowed t)))
|
||
|
||
(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))
|
||
#+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
|
||
|
||
* 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=
|
||
:PROPERTIES:
|
||
:header-args: :tangle ~/.config/doom/init.el
|
||
:END:
|
||
|
||
#+begin_src emacs-lisp
|
||
(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 ; tasing you for misspelling mispelling
|
||
|
||
:lang
|
||
data ; config/data formats
|
||
emacs-lisp ; drown in parentheses
|
||
go
|
||
(javascript
|
||
+lsp)
|
||
(latex
|
||
+latexmk
|
||
+lsp)
|
||
;; 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
|
||
+roam ;
|
||
+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: :tangle ~/.config/doom/packages.el
|
||
:END:
|
||
|
||
#+begin_src emacs-lisp
|
||
(package! vimrc-mode)
|
||
(package! poet-theme)
|
||
(package! spice-mode)
|
||
(package! org-pandoc-import
|
||
:recipe (:host github
|
||
:repo "tecosaur/org-pandoc-import"
|
||
:files ("*.el" "filters" "preprocessors")))
|
||
|
||
(package! citeproc-org)
|
||
(package! org-wild-notifier)
|
||
(package! org-gcal)
|
||
;; (package! ox-latex-subfigure
|
||
;; :recipe (:host github :repo "linktohack/ox-latex-subfigure"))
|
||
;; (package! matlab-mode)
|
||
(package! matlab-mode
|
||
:recipe (:host github :repo "matlab-mode/mirror"))
|
||
(package! org-ref)
|
||
(package! citeproc-org)
|
||
(package! org-ql)
|
||
(package! org-fancy-priorities)
|
||
(package! evil-escape :disable t)
|
||
(package! dired-narrow)
|
||
(package! web-server)
|
||
#+end_src
|