diff --git a/general/thesis.el b/general/thesis.el
index d5a2f80..7513a7d 100644
--- a/general/thesis.el
+++ b/general/thesis.el
@@ -19,6 +19,8 @@
(add-to-list 'package-archives
'("gnu" . "https://elpa.gnu.org/packages/")))
+(add-to-list 'package-archives '("org" . "https://orgmode.org/elpa/") t)
+
(unless (package-installed-p 'use-package)
(package-refresh-contents)
(package-install 'use-package))
@@ -34,3 +36,505 @@
(setq org-ref-completion-library 'org-ref-ivy-cite)
:config
(setq org-ref-default-citation-link "footcite"))
+
+(use-package org
+ :ensure t
+ :pin org
+ :config
+
+;; enable org-mode keys
+ (define-key global-map "\C-ca" 'org-agenda)
+ (global-set-key "\C-cl" 'org-store-link)
+ (global-set-key "\C-cc" 'org-capture)
+ (global-set-key "\C-cb" 'org-iswitchb)
+
+;; disable line split with M-RET
+(setq org-M-RET-may-split-line (quote ((default))))
+
+;; enable the correct intdentation for source code blocks
+(setq org-edit-src-content-indentation 0)
+(setq org-src-tab-acts-natively t)
+(setq org-src-preserve-indentation t)
+
+;; enable ido for org-mode
+;(setq org-completion-use-ido t)
+
+;; archive files to a monthly file
+(setq org-archive-location
+ (concat "~/git_repos/notes/personal/notes/archive/"
+ (format-time-string "%Y-%m" (current-time)) "-%s::datetree/"))
+;; enable todo and checkbox depencies
+(setq org-enforce-todo-dependencies t)
+(setq org-enforce-todo-checkbox-dependencies t)
+
+;; quick access for todo states
+(setq org-todo-keywords
+ '((sequence "TODO(t)" "NEXT(n)" "WAITING(w!)" "PROJECT(p)" "|" "DONE(d)")
+ (sequence "|" "CANCELLED(c)")))
+
+(setq org-log-done 'time)
+
+(setq org-log-into-drawer t)
+
+;; enable org-indent
+(setq org-startup-indented t)
+
+;; input templates
+(eval-after-load 'org
+ '(progn
+ (add-to-list 'org-structure-template-alist
+ '("p" "#+attr_latex: :center\n[[]]" "\n\n"))))
+
+;; capture templates
+ (setq org-capture-templates
+ (quote
+ (("j" "Journal" entry (file+datetree "~/git_repos/notes/personal/notes/journal.org")
+ "* %U\n\n%?" :empty-lines 1)
+ ("p" "Small Project" entry
+ (file+headline "~/git_repos/notes/personal/agenda/personal.org" "Capture")
+ (file "~/git_repos/notes/settings/templates/temp_personal_small_project.txt"))
+ ("t" "Adds a Next entry" entry
+ (file+headline "~/git_repos/notes/personal/agenda/personal.org" "Capture")
+ (file "~/git_repos/notes/settings/templates/temp_personal_todo.txt")
+ :empty-lines 1))))
+
+;; available effort times
+(setq org-global-properties
+ (quote
+ (("Effort_ALL" . "0 0:10 0:30 1:00 2:00 3:00 4:00 5:00 6:00 7:00"))))
+
+;; org-refile options
+(setq org-refile-allow-creating-parent-nodes (quote confirm))
+(setq org-refile-targets (quote ((org-agenda-files :maxlevel . 6))))
+(setq org-refile-use-outline-path 'file
+ org-outline-path-complete-in-steps nil)
+
+;; set to line seperator to 1
+(setq org-cycle-separator-lines 1)
+
+(setq org-src-fontify-natively t)
+
+(setq org-highlight-latex-and-related '(latex))
+
+(setq org-image-actual-width (quote (500)))
+(setq org-startup-with-inline-images t)
+
+(setq org-id-link-to-org-use-id 'create-if-interactive-and-no-custom-id
+ org-clone-delete-id t)
+
+(setq org-blank-before-new-entry
+ (quote ((heading . t)
+ (plain-list-item . auto))))
+
+(setq org-footnote-section "Resources")
+
+(setq org-attach-directory "~/nextcloud/03_documents/attachements/")
+
+(setq org-todo-keyword-faces
+ `(("WAITING" :foreground "#0087ff" :weight bold)
+ ("TODO" :foreground "#d75f00" :weight bold)
+ ("PROJECT" :foreground "#626262" :weight bold)
+ ("NEXT" :foreground "#d70000" :weight bold)))
+
+
+(set-face-attribute 'org-agenda-structure nil :inherit 'default :height 1.00)
+(set-face-attribute 'org-agenda-date-weekend nil :height 1.00 :weight 'medium)
+(set-face-attribute 'org-agenda-calendar-event nil :weight 'medium)
+(set-face-attribute 'org-agenda-date nil :inherit 'default :height 1.00 :weight 'bold)
+(set-face-attribute 'org-agenda-date-today nil :slant 'normal :weight 'bold :height 1.00)
+(set-face-attribute 'org-done nil :foreground "#5f8700" :weight 'bold)
+(set-face-attribute 'org-link nil :foreground "#0087ff" :underline t)
+(set-face-attribute 'org-scheduled nil :foreground "#5f8700" :slant 'italic :weight 'normal)
+(set-face-attribute 'org-scheduled-previously nil :foreground "#d70000" :weight 'normal)
+(set-face-attribute 'org-scheduled-today nil :foreground "#5f8700" :slant 'italic :weight 'normal)
+(set-face-attribute 'org-todo nil :background "nil" :foreground "#d70000" :weight 'bold)
+(set-face-attribute 'org-upcoming-deadline nil :foreground "#d70000" :weight 'normal)
+(set-face-attribute 'org-warning nil :foreground "#d70000" :weight 'normal)
+
+;; org-export formats
+;;(setq org-export-backends (quote (beamer html latex md odt reveal)))
+
+(setq org-html-html5-fancy t
+ org-html-doctype "html5")
+
+;; disable the Todo keywords in the export
+(setq org-export-with-todo-keywords nil)
+
+;; disable the tags in the export
+(setq org-export-with-tags nil)
+
+(setq org-latex-caption-above nil)
+
+(setq org-export-with-sub-superscripts nil)
+
+(setq org-export-with-smart-quotes t)
+
+(setq org-export-headline-levels 5)
+
+;; options for beamer exports
+(setq org-beamer-frame-level 2)
+(setq org-beamer-outline-frame-options "")
+(setq org-beamer-outline-frame-title "Inhalt")
+(setq org-beamer-theme "metropolis")
+
+;; options for latex exports
+(setq org-latex-classes
+ (quote
+ (("beamer" "\\documentclass{az_beamer}"
+ ("\\section{%s}" . "\\section*{%s}")
+ ("\\subsection{%s}" . "\\subsection*{%s}")
+ ("\\subsubsection{%s}" . "\\subsubsection*{%s}"))
+ ("article" "\\documentclass{article}"
+ ("\\section{%s}" . "\\section*{%s}")
+ ("\\subsection{%s}" . "\\subsection*{%s}")
+ ("\\subsubsection{%s}" . "\\subsubsection*{%s}")
+ ("\\paragraph{%s}" . "\\paragraph*{%s}")
+ ("\\subparagraph{%s}" . "\\subparagraph*{%s}"))
+ ("report" "\\documentclass[11pt]{report}"
+ ("\\part{%s}" . "\\part*{%s}")
+ ("\\chapter{%s}" . "\\chapter*{%s}")
+ ("\\section{%s}" . "\\section*{%s}")
+ ("\\subsection{%s}" . "\\subsection*{%s}")
+ ("\\subsubsection{%s}" . "\\subsubsection*{%s}"))
+ ("book" "\\documentclass[11pt]{book}"
+ ("\\part{%s}" . "\\part*{%s}")
+ ("\\chapter{%s}" . "\\chapter*{%s}")
+ ("\\section{%s}" . "\\section*{%s}")
+ ("\\subsection{%s}" . "\\subsection*{%s}")
+ ("\\subsubsection{%s}" . "\\subsubsection*{%s}")))))
+ (setq org-latex-default-packages-alist nil)
+ (setq org-latex-listings 'listings)
+ (setq org-latex-title-command "\\maketitle\\newpage")
+ (setq org-latex-toc-command "\\tableofcontents
+ \\newpage
+ ")
+
+;; Set the agenda separator to a space character.
+(setq org-agenda-block-separator " ")
+
+;; a function to call the custom agenda view.
+(defun az/custom-agenda (&optional arg)
+ (interactive "P")
+ (org-agenda arg "A"))
+
+(global-set-key [f9] 'az/custom-agenda)
+
+;; hide done tasks in the agenda
+(setq org-agenda-skip-deadline-if-done t)
+(setq org-agenda-skip-scheduled-if-done t)
+(setq org-agenda-skip-timestamp-if-done t)
+
+;; Custom agenda command to list the stuck projects in the normal
+;; agenda view.
+(setq org-stuck-projects '("/PROJECT" ("NEXT") nil ""))
+(setq org-agenda-custom-commands
+ (quote (("A" "Custom Agenda"
+ ((agenda "" nil)
+ (stuck ""
+ ((org-agenda-overriding-header "Stuck Projects")
+ (org-agenda-sorting-strategy
+ '(category-up))))
+ (tags-todo "TODO=\"PROJECT\" "
+ ((org-agenda-overriding-header "Projects")
+ (org-agenda-sorting-strategy
+ '(category-up))))
+ nil))
+ ;; Show all headings with the corresponding TODO state
+ ("N" occur-tree "NEXT")
+ ("O" occur-tree "TODO")
+ ("W" occur-tree "WAITING"))))
+
+;; don't show the warnings for deadlines if the item is scheduled
+(setq org-agenda-skip-deadline-prewarning-if-scheduled t)
+
+;; start the agenda on the current day and show the next 13 days
+(setq org-agenda-span 14
+ org-agenda-start-on-weekday nil)
+(setq org-agenda-tags-column -80)
+(setq org-agenda-show-future-repeats (quote next))
+(setq org-agenda-sorting-strategy
+ (quote
+ ((agenda todo-state-up priority-down category-up))))
+
+;; dimm open tasks
+(setq org-agenda-dim-blocked-tasks t)
+
+;; automatically refresh the agenda after adding a task
+(add-hook 'org-capture-after-finalize-hook 'nebucatnetzer:org-agenda-redo)
+
+(defun nebucatnetzer:org-agenda-redo ()
+(interactive)
+(when (get-buffer "*Org Agenda*")
+ (with-current-buffer "*Org Agenda*"
+ (org-agenda-redo t)
+ (message "[org agenda] refreshed!"))))
+
+(setq org-clock-out-remove-zero-time-clocks t)
+
+(defun start-heading-clock (id file)
+ "Start clock programmatically for heading with ID in FILE."
+ (require 'org-id)
+ (if-let (marker (org-id-find-id-in-file id file t))
+ (save-current-buffer
+ (save-excursion
+ (set-buffer (marker-buffer marker))
+ (goto-char (marker-position marker))
+ (org-clock-in)))
+ (warn "Clock not started (Could not find ID '%s' in file '%s')" id file)))
+
+(defun start-main-clock ()
+ "This functions always clocks in to the * Clock heading"
+ (interactive)
+ (start-heading-clock "e9f71012-4370-4dd2-af8e-9ae14d86508a" "~/git_repos/notes/work/agenda/work.org"))
+
+(global-set-key (kbd "") 'start-main-clock)
+
+(org-clock-persistence-insinuate)
+
+(setq org-clock-out-when-done t)
+
+(setq org-clock-persist t)
+;; Do not prompt to resume an active clock
+(setq org-clock-persist-query-resume nil)
+
+(global-set-key (kbd "") 'org-clock-in)
+(global-set-key (kbd "") 'org-clock-out)
+(global-set-key (kbd "C-x C-d") 'org-clock-mark-default-task)
+
+(setq org-duration-format (quote (("h") (special . 2))))
+
+(setq org-agenda-clockreport-parameter-plist
+ (quote (:link t :maxlevel 4 :tcolumns 3)))
+
+(defun directory-files-recursive (directory match maxdepth)
+ "List files in DIRECTORY and in its sub-directories.
+ Return files that match the regular expression MATCH. Recurse only
+ to depth MAXDEPTH. If zero or negative, then do not recurse"
+ (let* ((files-list '())
+ (current-directory-list
+ (directory-files directory t)))
+ ;; while we are in the current directory
+ (while current-directory-list
+ (let ((f (car current-directory-list)))
+ (cond
+ ((and
+ (file-regular-p f)
+ (file-readable-p f)
+ (string-match match f))
+ (setq files-list (cons f files-list)))
+ ((and
+ (file-directory-p f)
+ (file-readable-p f)
+ (not (string-equal ".." (substring f -2)))
+ (not (string-equal "." (substring f -1)))
+ (> maxdepth 0))
+ ;; recurse only if necessary
+ (setq files-list (append files-list (directory-files-recursive f match (- maxdepth -1))))
+ (setq files-list (cons f files-list)))
+ (t)))
+ (setq current-directory-list (cdr current-directory-list)))
+ files-list))
+
+ (defun tangle-all ()
+ (interactive)
+ "Tangle all the Org-mode files in the directory of the file of the current buffer
+ recursively in child folders. Returns the list of tangled files"
+ (mapcar (lambda (f)
+ (when (not (file-directory-p f))
+ (org-babel-tangle-file f)))
+ (directory-files-recursive (file-name-directory (buffer-file-name)) "\\.org$" 20)))
+
+(defadvice org-babel-execute-src-block (around load-language nil activate)
+ "Load language if needed"
+ (let ((language (org-element-property :language (org-element-at-point))))
+ (unless (cdr (assoc (intern language) org-babel-load-languages))
+ (add-to-list 'org-babel-load-languages (cons (intern language) t))
+ (org-babel-do-load-languages 'org-babel-load-languages org-babel-load-languages))
+ ad-do-it))
+
+ (setq org-plantuml-jar-path "~/.emacs.d/plantuml.jar")
+;; end of the org-mode use-package block
+
+(defun my/fix-inline-images ()
+(when org-inline-image-overlays
+ (org-redisplay-inline-images)))
+
+(add-hook 'org-babel-after-execute-hook 'my/fix-inline-images)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; add image from conference phone upload ;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; use case is taking a photo of a slide in a conference and uploading
+;; it to google drive or dropbox or whatever to get it on your
+;; computer. You then want to embed it in an org-mode document by
+;; moving it to the same folder and renaming according to the current
+;; section of the org file, avoiding name clashes
+
+;; required libraries
+(require 'dash)
+(require 'swiper)
+(require 's)
+
+(global-set-key (kbd "C-c i") 'org-insert-image)
+;; start directory
+ (defvar bjm/conference-image-dir (expand-file-name "/home/andreas/Downloads/")))
+
+(defun org-insert-image ()
+ "Insert image from conference directory, rename and add link in current file.
+ The file is taken from a start directory set by
+ `bjm/conference-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 bjm/conference-image-dir)))
+
+ ;; get target directory
+ (setq target-dir (file-name-directory (buffer-file-name)))
+
+ ;; sort list by most recent
+ ;; http://stackoverflow.com/questions/26514437/emacs-sort-list-of-directories-files-by-modification-date
+ (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 bjm/conference-image-dir))
+ ;; generate target file name from current org section
+ (setq file-ext
+ (file-name-extension start-file t))
+
+ ;; my phone app doesn't add an extension to the image so I do it
+ ;; here. If you want to keep the existing extension then use the
+ ;; line above
+ ;;(setq file-ext ".jpg")
+ ;; get section heading and clean it up
+ (setq end-file-base (s-downcase (s-dashed-words (nth 4 (org-heading-components)))))
+ ;; shorten to first 40 chars to avoid long file names
+ (setq end-file-base (s-left 40 end-file-base))
+ ;; number to append to ensure unique name
+ (setq file-number 1)
+ (setq end-file (concat
+ end-file-base
+ (format "-%s" file-number)
+ file-ext))
+
+ ;; increment number at end of name if file exists
+ (while (file-exists-p end-file)
+ ;; increment
+ (setq file-number (+ file-number 1))
+ (setq end-file (concat
+ end-file-base
+ (format "-%s" file-number)
+ file-ext)))
+
+ ;; final file name including path
+ (setq end-file-full
+ (expand-file-name end-file target-dir))
+ ;; rename file
+ (rename-file start-file-full end-file-full)
+ (message "moved %s to %s" start-file-full end-file)
+ ;; insert link
+ (insert (org-make-link-string (format "file:%s" end-file)))
+ ;; display image
+ (org-display-inline-images t t))
+
+(load-library "find-lisp")
+ (setq org-agenda-files
+ (find-lisp-find-files "~/git_repos/notes/personal/agenda" "\.org$"))
+
+(defun org-update-cookies-after-save()
+(interactive)
+(let ((current-prefix-arg '(4)))
+(org-update-statistics-cookies "ALL")))
+
+(add-hook 'org-mode-hook
+ (lambda ()
+ (add-hook 'before-save-hook 'org-update-cookies-after-save nil 'make-it-local)))
+
+(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"))))
+
+(add-hook 'org-after-todo-statistics-hook 'org-summary-todo))
+
+;; keymap for my personal.org file
+ (global-set-key (kbd "C-c p")
+ (lambda () (interactive) (find-file "~/git_repos/notes/personal/agenda/personal.org")))
+
+(defun lower-case-org-keywords ()
+ "Lower case Org keywords and block identifiers.
+
+Example: \"#+TITLE\" -> \"#+title\"
+ \"#+BEGIN_EXAMPLE\" -> \"#+begin_example\"
+
+Inspiration:
+https://code.orgmode.org/bzg/org-mode/commit/13424336a6f30c50952d291e7a82906c1210daf0."
+ (interactive)
+ (save-excursion
+ (goto-char (point-min))
+ (let ((case-fold-search nil)
+ (count 0))
+ ;; Match examples: "#+foo bar", "#+foo:", "=#+foo=", "~#+foo~",
+ ;; "‘#+foo’", "“#+foo”", ",#+foo bar",
+ ;; "#+FOO_bar", "#+FOO".
+ (while (re-search-forward "\\(?1:#\\+[A-Z_]+\\(?:_[[:alpha:]]+\\)*\\)\\(?:[ :=~’”]\\|$\\)" nil :noerror)
+ (setq count (1+ count))
+ (replace-match (downcase (match-string-no-properties 1)) :fixedcase nil nil 1))
+ (message "Lower-cased %d matches" count))))
+
+(with-eval-after-load 'org
+(define-key org-mode-map (kbd "C-c m") 'org-mantis-open)
+
+(defun org-pom (pom)
+ "If in an agenda buffer, org-pom returns the marker of the
+corresponding org entry. Otherwise return marker."
+ (interactive "d")
+ (get-text-property pom 'org-marker))
+
+(defun org-mantis-get (pom)
+ "Retrieve mantis property at point, POM"
+ (interactive "d")
+ (org-entry-get (org-pom pom) "mantis"))
+
+(defun org-mantis-kill (pom)
+ "Add mantis ticket of item at POM to killring"
+ (interactive "d")
+ (kill-new (format "%s" (org-mantis-get pom))))
+
+(defun org-mantis-set (pom)
+ "Given a ticket number, set the mantis property to -`ticket`
+at point, POM"
+ (interactive "d")
+ (setq ticket (org-mantis-get pom))
+ (if ticket
+ (setq default_str (format " (default %s)" ticket))
+ (setq default_str ""))
+ (setq ticket (read-from-minibuffer (format "ticket%s: " default_str)))
+ (org-entry-put (org-pom pom) "mantis" ticket))
+
+(defun org-mantis-open (pre pom)
+ "Open mantis ticket in browser if org property 'mantis' is set at POM,
+otherwise prompt the user for a software ticket number"
+ (interactive "P\nd")
+ (if pre
+ (org-mantis-set pom)
+ (if (org-mantis-get pom)
+ (browse-url (format "https://contria.mantishub.io/view.php?id=%s"
+ (org-mantis-get pom)))
+ (org-mantis-set pom)))))