org-thesis/org-init.el

592 lines
23 KiB
EmacsLisp

;; Possibly relevant configuration for org-thesis
;;;;;;;;;;;;;;
;; Straight ;;
;;;;;;;;;;;;;;
;; Straight.el is a functional package manager for Emacs. It server as
;; a replacement for the native package.el
(setq-default straight-repository-branch "develop")
;; Bootstrap the package manager, straight.el.
(defvar bootstrap-version)
(let ((bootstrap-file
(expand-file-name "straight/repos/straight.el/bootstrap.el" user-emacs-directory))
(bootstrap-version 5))
(unless (file-exists-p bootstrap-file)
(with-current-buffer
(url-retrieve-synchronously
"https://raw.githubusercontent.com/raxod502/straight.el/develop/install.el"
'silent 'inhibit-cookies)
(goto-char (point-max))
(eval-print-last-sexp)))
(load bootstrap-file nil 'nomessage))
(defun straight-reload-init ()
"Reload init.el."
(interactive)
(straight-transaction
(straight-mark-transaction-as-init)
(message "Reloading init.el...")
(load user-init-file nil 'nomessage)
(message "Reloading init.el... done.")))
;;;;;;;;;;;;;;;;;
;; use-package ;;
;;;;;;;;;;;;;;;;;
;; Use-package is a declarative package configurator.
;; We need to set some configurations before "requiring" use-package, so that it
;; integrates better with imenu and this init file.
(setq-default use-package-enable-imenu-support t
use-package-form-regexp-eval
`(concat ,(eval-when-compile
(concat "^\\s-*("
(regexp-opt '("use-package" "use-feature" "require") t)
"\\s-+\\("))
(or (bound-and-true-p lisp-mode-symbol-regexp)
"\\(?:\\sw\\|\\s_\\|\\\\.\\)+") "\\)"))
;; Call straight-use-package to bootstrap use-package so we can use it.
(straight-use-package 'use-package)
(defmacro use-feature (name &rest args)
"Like `use-package', but with `straight-use-package-by-default' disabled."
(declare (indent defun))
`(use-package ,name
:straight nil
,@args))
;; When configuring a feature with `use-package', also tell
;; straight.el to install a package of the same name, unless otherwise
;; specified using the `:straight' keyword.
(setq-default straight-use-package-by-default t)
;; Tell `use-package' to always load features lazily unless told
;; otherwise. It's nicer to have this kind of thing be deterministic:
;; if `:demand' is present, the loading is eager; otherwise, the
;; loading is lazy. See
;; https://github.com/jwiegley/use-package#notes-about-lazy-loading.
(setq-default use-package-always-defer t)
;;;;;;;;;;;;;;
;; Org Mode ;;
;;;;;;;;;;;;;;
;; Our real configuration for Org comes much later. Doing this now
;; means that if any packages that are installed in the meantime
;; depend on Org, they will not accidentally cause the Emacs-provided
;; (outdated and duplicated) version of Org to be loaded before the
;; real one is registered.
(use-package org
:ensure org-contrib)
;; Here we guarantee that org mode gets loaded properly.
(use-package org-contrib)
;; Here we guarantee that org mode gets loaded properly.
(use-feature org
;; See an inspirational Org config here: https://github.com/novoid/dot-emacs/blob/master/config.org
:config
(setq-default org-catch-invisible-edits 'smart
org-special-ctrl-a/e t
org-image-actual-width '(400)
org-return-follows-link t
org-list-allow-alphabetical t
;; Aesthetics
org-blank-before-new-entry '((heading . t) (plain-list-item . nil))
org-fontify-quote-and-verse-blocks t
org-hide-macro-markers nil
org-fontify-whole-heading-line t
org-fontify-done-headline t
org-hide-emphasis-markers nil
org-highlight-latex-and-related '(latex)
;; Image display
org-image-actual-width '(400)
;; Agenda
org-deadline-warning-days 40
org-deadline-past-days 21)
(add-to-list 'org-structure-template-alist '("el" . "src emacs-lisp"))
(add-to-list 'org-structure-template-alist '("sh" . "src sh"))
(add-to-list 'org-structure-template-alist '("py" . "src python"))
(add-to-list 'org-structure-template-alist '("j" . "src jupyter-python"))
;; After inserting an org template, also open a line.
(defun org-structure-template-and-open-line (orig-func &rest args)
(apply orig-func args)
(unless mark-active
(open-line 1)))
(advice-add 'org-insert-structure-template
:around #'org-structure-template-and-open-line)
(defun scimax/org-return (&optional ignore)
"Add new list item, heading or table row with RET.
A double return on an empty element deletes it.
Use a prefix arg to get regular RET. "
(interactive "P")
(if ignore
(org-return)
(cond
((eq 'line-break (car (org-element-context)))
(org-return-indent))
;; Open links like usual, unless point is at the end of a line.
;; and if at beginning of line, just press enter.
((or (and (eq 'link (car (org-element-context))) (not (eolp)))
(bolp))
(org-return))
;; checkboxes too
((org-at-item-checkbox-p)
(if (org-element-property :contents-begin
(org-element-context))
;; we have content so add a new checkbox
(org-insert-todo-heading nil)
;; no content so delete it
(setf (buffer-substring (line-beginning-position) (point)) "")
(org-return)))
;; lists end with two blank lines, so we need to make sure we are also not
;; at the beginning of a line to avoid a loop where a new entry gets
;; created with only one blank line.
((org-in-item-p)
(if (save-excursion
(beginning-of-line) (org-element-property :contents-begin (org-element-context)))
(org-insert-item)
(beginning-of-line)
(delete-region (line-beginning-position) (line-end-position))
(org-return)))
;; org-heading
((org-at-heading-p)
(if (not (string= "" (org-element-property :title (org-element-context))))
(progn
;; Go to end of subtree suggested by Pablo GG on Disqus post.
(org-end-of-subtree)
(org-insert-heading-respect-content)
(outline-show-entry))
;; The heading was empty, so we delete it
(beginning-of-line)
(setf (buffer-substring
(line-beginning-position) (line-end-position)) "")))
;; tables
((org-at-table-p)
(if (-any?
(lambda (x) (not (string= "" x)))
(nth
(- (org-table-current-dline) 1)
(remove 'hline (org-table-to-lisp))))
(org-return)
;; empty row
(beginning-of-line)
(setf (buffer-substring
(line-beginning-position) (line-end-position)) "")
(org-return)))
;; fall-through case
(t
(org-return)))))
(defmacro unpackaged/def-org-maybe-surround (&rest keys)
"Define and bind interactive commands for each of KEYS that surround the region or insert text.
Commands are bound in `org-mode-map' to each of KEYS. If the
region is active, commands surround it with the key character,
otherwise call `org-self-insert-command'."
`(progn
,@(cl-loop for key in keys
for name = (intern (concat "unpackaged/org-maybe-surround-" key))
for docstring = (format "If region is active, surround it with \"%s\", otherwise call `org-self-insert-command'." key)
collect `(defun ,name ()
,docstring
(interactive)
(if (region-active-p)
(let ((beg (region-beginning))
(end (region-end)))
(save-excursion
(goto-char end)
(insert ,key)
(goto-char beg)
(insert ,key)))
(call-interactively #'org-self-insert-command)))
collect `(define-key org-mode-map (kbd ,key) #',name))))
(unpackaged/def-org-maybe-surround "~" "=" "*" "/" "+" "$")
(defun org-summary-todo (n-done n-not-done)
"Switch entry to DONE when all subentries are done, to TODO otherwise."
(let (org-log-done org-log-states) ; turn off logging
(org-todo (if (= n-not-done 0) "DONE" "TODO"))))
:hook ((org-after-todo-statistics . org-summary-todo)
(org-mode . visual-line-mode)
(org-mode . visual-fill-column-mode)
(org-mode . flycheck-mode)
;; (org-mode . flyspell-mode) ; Flyspell-mode bug when used with company. Activate only when necessary.
(org-mode . (lambda ()
(push '("#+begin_src" . "λ") prettify-symbols-alist)
(push '("#+end_src" . "λ") prettify-symbols-alist)
(push '("#+begin_example" . "") prettify-symbols-alist)
(push '("#+end_example" . "") prettify-symbols-alist)
(push '("#+begin_quote" . "") prettify-symbols-alist)
(push '("#+end_quote" . "") prettify-symbols-alist)
(push '("#+begin_export" . "->") prettify-symbols-alist)
(push '("#+end_export" . "<-") prettify-symbols-alist)
(push '("jupyter-python" . "") prettify-symbols-alist)
(push '("#+RESULTS:" . "=") prettify-symbols-alist)
(push '(":results" . "=") prettify-symbols-alist)
(push '(":dir" . "") prettify-symbols-alist)
(push '(":session" . "@") prettify-symbols-alist)
(setq line-spacing 4)
(prettify-symbols-mode))))
:bind (:map org-mode-map
("RET" . scimax/org-return)))
(use-feature org-src
:after org
:demand t
:config
(setq-default org-edit-src-content-indentation 0
org-src-preserve-indentation t
org-src-fontify-natively t))
(use-feature ob
:after org
:demand t
:config
(setq-default org-confirm-babel-evaluate nil
org-confirm-elisp-link-function nil
org-confirm-shell-link-function nil)
(dolist (language '((org . t)
(python . t)
(matlab . t)
(shell . t)
(latex . t)))
(add-to-list 'org-babel-load-languages language))
(org-babel-do-load-languages 'org-babel-load-languages org-babel-load-languages)
:hook (org-babel-after-execute . org-display-inline-images))
(use-feature ox
:after org
:demand t
:config
;; This is so that we are not queried if bind-keywords are safe when we set
;; org-export-allow-bind to t.
(put 'org-export-allow-bind-keywords 'safe-local-variable #'booleanp)
(setq org-export-with-sub-superscripts '{}
org-export-coding-system 'utf-8
org-html-checkbox-type 'html))
;; Once I reach feature parity with my old Spacemacs setup I should
;; make these configurations into a dedicated module.
(use-feature ox-latex
:after ox
:demand t
:init (setq org-latex-pdf-process
'("latexmk -pdflatex='pdflatex -shell-escape -interaction nonstopmode' -pdf -bibtex -f %f"))
:config
;; Sometimes it's good to locally override these two.
(put 'org-latex-title-command 'safe-local-variable #'stringp)
(put 'org-latex-toc-command 'safe-local-variable #'stringp)
;; Need to let ox know about ipython and jupyter
(add-to-list 'org-latex-minted-langs '(ipython "python"))
(add-to-list 'org-babel-tangle-lang-exts '("ipython" . "py"))
(add-to-list 'org-latex-minted-langs '(jupyter-python "python"))
(add-to-list 'org-babel-tangle-lang-exts '("jupyter-python" . "py"))
;; Mimore class is a latex class for writing articles.
(add-to-list 'org-latex-classes
'("mimore"
"\\documentclass{mimore}
[NO-DEFAULT-PACKAGES]
[PACKAGES]
[EXTRA]"
("\\section{%s}" . "\\section*{%s}")
("\\subsection{%s}" . "\\subsection*{%s}")
("\\subsubsection{%s}" . "\\subsubsection*{%s}")
("\\paragraph{%s}" . "\\paragraph*{%s}")
("\\subparagraph{%s}" . "\\subparagraph*{%s}")))
;; Mimosis is a class I used to write my Ph.D. thesis.
(add-to-list 'org-latex-classes
'("mimosis"
"\\documentclass{mimosis}
[NO-DEFAULT-PACKAGES]
[PACKAGES]
[EXTRA]
\\newcommand{\\mboxparagraph}[1]{\\paragraph{#1}\\mbox{}\\\\}
\\newcommand{\\mboxsubparagraph}[1]{\\subparagraph{#1}\\mbox{}\\\\}"
("\\chapter{%s}" . "\\chapter*{%s}")
("\\section{%s}" . "\\section*{%s}")
("\\subsection{%s}" . "\\subsection*{%s}")
("\\subsubsection{%s}" . "\\subsubsection*{%s}")
("\\mboxparagraph{%s}" . "\\mboxparagraph*{%s}")
("\\mboxsubparagraph{%s}" . "\\mboxsubparagraph*{%s}")))
;; Elsarticle is Elsevier class for publications.
(add-to-list 'org-latex-classes
'("elsarticle"
"\\documentclass{elsarticle}
[NO-DEFAULT-PACKAGES]
[PACKAGES]
[EXTRA]"
("\\section{%s}" . "\\section*{%s}")
("\\subsection{%s}" . "\\subsection*{%s}")
("\\subsubsection{%s}" . "\\subsubsection*{%s}")
("\\paragraph{%s}" . "\\paragraph*{%s}")
("\\subparagraph{%s}" . "\\subparagraph*{%s}")))
(setq org-latex-prefer-user-labels t))
;; Feature `ox-extra' is a library from the org-plus-contrib package.
;; It adds extra keywords and tagging functionality for org export.
(use-feature ox-extra
;; Demand so that ignore headlines is always active.
:demand t
:after ox
;; The ignore-headlines allows Org to understand the tag :ignore: and simply
;; remove tagged headings on export, but leave their content in.
;; See my blog post about writing thesis with org mode here:
;; https://write.as/dani/writing-a-phd-thesis-with-org-mode
:config (ox-extras-activate '(ignore-headlines)))
;; Feature `org-compat' is a adapter layer so that org can communicate with other Emacs
;; built-in packages.
(use-feature org-compat
:demand t
:after org
:config (setq org-imenu-depth 3))
;; Org-keys adds speed keys when cursor is at the beginning of a heading
(use-feature org-keys
:demand t
:after org
:config (setq org-use-speed-commands t
org-speed-commands-user '(("S" . org-store-link))))
;; Package `ob-async' allows executing ob commands asynchronously.
(use-package ob-async
:disabled t
:after ob
:config
;; Jupyter defines its own async that conflicts with ob-async.
(setq ob-async-no-async-languages-alist '("jupyter-python" "jupyter-julia")))
;; The `ox-word' library uses pandoc to export Org files to Microsoft Word via
;; LaTeX. It is currently a part of Kitchin's awesome Scimax project.
(use-package ox-word
:after (:all org-ref ox)
:demand t
:straight (ox-word :type git
:host github
:repo "jkitchin/scimax"
:files ("ox-word.el")))
;; The `org-ref' package adds functionality to manage, insert and navigate
;; citations (and other references as well, such as equations) within Org mode.
(use-package org-ref
:straight (org-ref :type git :host github :repo "jkitchin/org-ref" :branch "org-ref-2")
:after org
:demand t ;; Ensure that it loads so that links work immediately.
:config
(setq org-ref-default-bibliography '("~/project/org-thesis/thesis/thesis.bib")
org-ref-get-pdf-filename-function 'org-ref-get-pdf-filename-helm-bibtex
bibtex-completion-pdf-field "file"
org-ref-default-citation-link "parencite")
(defun org-ref-grep-pdf (&optional _candidate)
"Search pdf files of marked CANDIDATEs."
(interactive)
(let ((keys (helm-marked-candidates))
(get-pdf-function org-ref-get-pdf-filename-function))
(helm-do-pdfgrep-1
(-remove (lambda (pdf)
(string= pdf ""))
(mapcar (lambda (key)
(funcall get-pdf-function key))
keys)))))
(defun org-ref-open-pdf-at-point-in-emacs ()
"Open the pdf 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)
(find-file-other-window pdf-file)
(message "no pdf found for %s" key))))
(defun org-ref-open-in-scihub ()
"Open the bibtex entry at point in a browser using the url field or doi field.
Not for real use, just here for demonstration purposes."
(interactive)
(let ((doi (org-ref-get-doi-at-point)))
(when doi
(if (string-match "^http" doi)
(browse-url doi)
(browse-url (format "http://sci-hub.se/%s" doi)))
(message "No url or doi found"))))
(helm-add-action-to-source "Grep PDF" 'org-ref-grep-pdf helm-source-bibtex 1)
;; The following makes it possible to grep pdfs from the org-ref Helm
;; selection interface with C-s.
(setq helm-bibtex-map
(let ((map (make-sparse-keymap)))
(set-keymap-parent map helm-map)
(define-key map (kbd "C-s") (lambda () (interactive)
(helm-run-after-exit 'org-ref-grep-pdf)))
map))
(push `(keymap . ,helm-bibtex-map) helm-source-bibtex)
(setq org-ref-helm-user-candidates
'(("Open in Sci-hub" . org-ref-open-in-scihub)
("Open in Emacs" . org-ref-open-pdf-at-point-in-emacs))))
(use-package org-brain
:init
(setq org-brain-path "~/org/knowledge")
(defun org-brain-insert-resource-icon (link)
"Insert an icon, based on content of org-mode LINK."
(insert (format "%s "
(cond ((string-prefix-p "http" link)
(cond ((string-match "wikipedia\\.org" link)
(all-the-icons-faicon "wikipedia-w"))
((string-match "github\\.com" link)
(all-the-icons-octicon "mark-github"))
((string-match "vimeo\\.com" link)
(all-the-icons-faicon "vimeo"))
((string-match "youtube\\.com" link)
(all-the-icons-faicon "youtube"))
((string-match "imdb\\.com" link)
(all-the-icons-material "movie"))
(t
(all-the-icons-faicon "globe"))))
((string-prefix-p "brain:" link)
(all-the-icons-fileicon "brain"))
((string-prefix-p "cite:" link)
(all-the-icons-material "book"))
((string-prefix-p "parencite:" link)
(all-the-icons-material "book"))
(t
(all-the-icons-icon-for-file link))))))
:config
(setq org-id-track-globally t)
(setq org-id-locations-file "~/.emacs.d/.org-id-locations")
(setq org-brain-visualize-default-choices 'all)
(setq org-brain-title-max-length 100)
(defun org-brain-open-org-noter (entry)
"Open `org-noter' on the ENTRY.
If run interactively, get ENTRY from context."
(interactive (list (org-brain-entry-at-pt)))
(org-with-point-at (org-brain-entry-marker entry)
(org-noter)))
:commands org-brain-visualize
:bind (:map org-brain-visualize-mode-map
("C-c n" . org-brain-open-org-noter))
:hook
(org-brain-visualize-mode . visual-line-mode)
(org-brain-after-resource-button-functions . org-brain-insert-resource-icon))
(use-package org-cliplink
:defer 5
:after org)
(use-package org-noter
:after org
:commands org-noter
:config (setq org-noter-default-notes-file-names nil
;; org-noter-always-create-frame nil
org-noter-notes-search-path '("~/org/Research-Notes")
org-noter-separate-notes-from-heading t))
;; Feature org-protocol is a part of org-plus-contrib.
(use-feature org-protocol
:demand 5
:after org
:init
(defun transform-square-brackets-to-round-ones(string-to-transform)
"Transforms [ into ( and ] into ), other chars left unchanged."
(concat
(mapcar #'(lambda (c) (if (equal c ?\[) ?\( (if (equal c ?\]) ?\) c))) string-to-transform)))
:config
(setq org-capture-templates '(("t" "Todo [inbox]" entry
(file+headline "~/gtd/inbox.org" "Tasks")
"* TODO %i%?")
("T" "Tickler" entry
(file+headline "~/gtd/tickler.org" "Tickler")
"* %i%? \n %U")
("p" "Protocol" entry
(file+headline "~/gtd/inbox.org" "Inbox")
"* %^{Title}\nSource: [[%:link]] %u, %c\n #+BEGIN_QUOTE\n%i\n#+END_QUOTE\n\n\n %?")
("L" "Protocol Link" entry
(file+headline "~/gtd/inbox.org" "Inbox")
"* %? [[%:link][%(transform-square-brackets-to-round-ones \"%:description\")]] %U\n")))
(setq org-refile-targets '(("~/gtd/gtd.org" :maxlevel . 3)
("~/gtd/someday.org" :level . 1)
("~/gtd/readings.org" :maxlevel . 1)
("~/gtd/random.org" :maxlevel . 1)
("~/gtd/learning.org" :level . 1)
("~/gtd/tickler.org" :maxlevel . 2)))
(setq org-agenda-files '("~/gtd/inbox.org"
"~/gtd/gtd.org"
"~/gtd/tickler.org")))
;; Package org-download allows drag and drop of images directly into Emacs org-mode.
(use-package org-download
:after org
:demand t
:commands (org-download-enable
org-download-yank
org-download-screenshot)
:config
(setq-default org-download-image-dir "./img")
(setq org-download-screenshot-method "screencapture -i %s")
:hook ((org-mode dired-mode) . org-download-enable))
;;;;;;;;;;;
;; Latex ;;
;;;;;;;;;;;
(use-package auctex)
(use-feature tex
:config
(setq-default TeX-auto-save t
TeX-PDF-mode t
Tex-show-compilation nil
TeX-parse-self t)
:hook ((LaTeX-mode . visual-line-mode)
(LaTeX-mode . (lambda ()
(add-to-list
'TeX-command-list
'("XeLaTeX" "%`xelatex%(mode)%' %t" TeX-run-TeX nil t))))))
(use-feature tex-buf
:config
(setq TeX-save-query nil))
(use-package company-auctex
:demand t
:after (:all company tex)
:config
(company-auctex-init))
(use-package scimax-latex
:straight (scimax-latex :type git
:host github
:repo "jkitchin/scimax"
:files ("scimax-latex.el"))
:commands (scimax-latex-setup
kpsewhich
texdoc))