480 lines
20 KiB
EmacsLisp
480 lines
20 KiB
EmacsLisp
;;; org.el -*- lexical-binding: t; -*-
|
|
|
|
(after! org
|
|
(setq
|
|
calendar-week-start-day 1
|
|
org-agenda-columns-add-appointments-to-effort-sum t
|
|
org-agenda-default-appointment-duration 30
|
|
org-agenda-file-regexp (format-time-string "\\`[^.].*\\.org\\'\\|\\`%Y%m[0-9]+\\'")
|
|
org-agenda-hide-tags-regexp "presents"
|
|
org-agenda-include-diary nil
|
|
org-agenda-ndays 1
|
|
org-agenda-start-day nil
|
|
org-agenda-show-inherited-tags (quote always)
|
|
org-agenda-skip-deadline-if-done t
|
|
org-agenda-skip-scheduled-if-deadline-is-shown t
|
|
org-agenda-skip-scheduled-if-done t
|
|
org-agenda-span 1
|
|
org-agenda-start-with-clockreport-mode nil
|
|
org-agenda-sticky nil
|
|
org-agenda-tags-column -105
|
|
org-agenda-time-leading-zero t
|
|
org-agenda-with-colors t
|
|
org-agenda-dim-blocked-tasks nil
|
|
org-agenda-inhibit-startup t
|
|
org-agenda-use-tag-inheritance nil
|
|
org-alert-notification-title "OrgMode"
|
|
org-archive-location "%s_archive::"
|
|
org-clock-in-resume t
|
|
org-clock-out-remove-zero-time-clocks t
|
|
org-clock-persist t
|
|
org-clock-persist-query-resume nil
|
|
org-persist-directory (concat user-emacs-directory "org/persist/" (or (getenv "EMACS_SERVER_NAME") "default"))
|
|
org-clock-report-include-clocking-task t
|
|
org-clock-sound t
|
|
org-columns-default-format "%80ITEM(Task) %10Effort(Effort){:} %10CLOCKSUM"
|
|
org-confirm-babel-evaluate nil
|
|
org-duration-format (quote (("h" . t) (special . 2)))
|
|
org-link-elisp-confirm-function nil
|
|
org-deadline-warning-days 5
|
|
org-default-notes-file "~/Documents/Zettelkasten/refile.org"
|
|
org-ellipsis " ⧩ "
|
|
org-habit-following-days 3
|
|
org-habit-graph-column 60
|
|
org-habit-show-habits-only-for-today nil
|
|
org-habit-today-glyph ?‖
|
|
org-habit-completed-glyph ?✰
|
|
org-habit-show-all-today t
|
|
org-hide-emphasis-markers t
|
|
org-hide-leading-stars nil
|
|
org-indent-mode-turns-on-hiding-stars nil
|
|
org-icalendar-alarm-time 120
|
|
org-icalendar-combined-agenda-file "~/Nextcloud/OrgExport/Org.ics"
|
|
org-icalendar-include-todo (quote all)
|
|
org-icalendar-store-UID t
|
|
org-icalendar-timezone "UTC+2:00"
|
|
org-icalendar-use-deadline (quote (event-if-todo todo-due))
|
|
org-icalendar-use-scheduled (quote (event-if-todo todo-start))
|
|
org-icalendar-with-timestamps nil
|
|
org-log-done t
|
|
org-mu4e-link-query-in-headers-mode nil
|
|
org-outline-path-complete-in-steps nil
|
|
org-pretty-entities t
|
|
org-refile-allow-creating-parent-nodes 'confirm
|
|
org-refile-history nil
|
|
org-refile-targets '((org-agenda-files . (:maxlevel . 4)))
|
|
org-refile-use-outline-path 'file
|
|
org-return-follows-link t
|
|
org-scheduled-delay-days 0
|
|
+org-capture-emails-file "Todo.org"
|
|
org-show-notification-handler "notify-send"
|
|
org-startup-folded t
|
|
org-tag-faces (quote (("next" . "red") ("waiting" . "blue")))
|
|
counsel-org-goto-all-outline-path-prefix 'file-name-nondirectory
|
|
)
|
|
|
|
(setq org-directory (expand-file-name (if (string= (system-name) "apfelstrudel")
|
|
"~/Work/Zettelkasten"
|
|
"~/Documents/Zettelkasten")))
|
|
|
|
(setq org-agenda-files (list org-directory))
|
|
|
|
(setq org-agenda-current-time-string " ┈ now ┈ ")
|
|
|
|
|
|
|
|
(setq org-capture-templates
|
|
(if (string= (system-name) "apfelstrudel")
|
|
'(("t" "Todo" entry (file "Todo.org")
|
|
"* TODO %?\n %i")
|
|
("m" "MailTodo" entry (file "Todo.org")
|
|
"* TODO %:fromname %a%?\nSCHEDULED: %(org-insert-time-stamp (org-read-date nil t \"+0d\"))\n%i\n")
|
|
("p" "OpsRetro positive" entry (file+olp "Alfaview.org" "Meetings" "Ops-Retro") "* TODO :+1: %?\n %i")
|
|
("n" "OpsRetro negative" entry (file+olp "Alfaview.org" "Meetings" "Ops-Retro") "* TODO :-1: %?\n %i"))
|
|
'(("t" "Todo" entry (file "Todo.org")
|
|
"* TODO %?\n %i")
|
|
("m" "MailTodo" entry (file "Todo.org")
|
|
"* TODO %:fromname %a%?\nSCHEDULED: %(org-insert-time-stamp (org-read-date nil t \"+0d\"))\n%i\n")
|
|
("p" "Print" entry (file+headline "Personal.org" "Drucken")
|
|
"* TODO %a drucken :@home:@print:%?\nSCHEDULED: %(org-insert-time-stamp (org-read-date nil t \"+1d\"))\n%a\n")
|
|
("b" "BlogIdeas" entry (file+olp "Projects.org" "bascht.com" "BlogIdeas")
|
|
"* TODO %?\n %i"))))
|
|
|
|
(custom-theme-set-faces
|
|
'user
|
|
`(org-level-3 ((t (:height 1.1 :weight light))))
|
|
`(org-level-2 ((t (:height 1.2 :weight light))))
|
|
`(org-level-1 ((t (:height 1.3 :weight normal))))
|
|
`(org-document-title ((t (:height 1.5 :underline nil)))))
|
|
|
|
;; Resume clocking task when emacs is restarted
|
|
(org-clock-persistence-insinuate)
|
|
|
|
(setq org-agenda-time-grid
|
|
(quote
|
|
((daily require-timed)
|
|
(800 900 1000 1100 1200 1300 1400 1500 1600 1700 1800 1900 2000)
|
|
"......" "───────────────")))
|
|
|
|
(setq org-modules
|
|
(quote (org-habit
|
|
org-checklist
|
|
org-mouse)))
|
|
|
|
(setq org-agenda-custom-commands
|
|
'(("l" "Open loops"
|
|
((agenda ""))
|
|
((org-agenda-start-day "-1d")
|
|
;; (org-agenda-span 'week)
|
|
(org-agenda-show-log nil)
|
|
(org-agenda-ndays 2)
|
|
(tags-todo "-imported")
|
|
(org-agenda-start-with-clockreport-mode nil)
|
|
(org-agenda-skip-function '(org-agenda-skip-entry-if 'todo 'done))
|
|
(org-agenda-start-with-log-mode '(closed clock state) )))
|
|
("h" "Daily habits"
|
|
((agenda ""))
|
|
((org-agenda-show-log t)
|
|
(org-agenda-ndays 7)
|
|
(org-agenda-log-mode-items '(state))
|
|
(org-agenda-skip-function '(org-agenda-skip-entry-if 'notregexp ":DAILY:"))))
|
|
("u" "Super view"
|
|
((agenda "" ((org-super-agenda-groups
|
|
'((:name "Today"
|
|
:time-grid t)))))
|
|
(todo "" ((org-agenda-overriding-header "Projects")
|
|
(org-super-agenda-groups
|
|
'((:name none ; Disable super group header
|
|
:children todo)
|
|
(:discard (:anything t))))))))
|
|
("P" agenda "Printable"
|
|
((ps-number-of-columns 2)
|
|
(ps-landscape-mode t)
|
|
(org-agenda-prefix-format " - [ ] ")
|
|
(org-agenda-with-colors t)
|
|
(org-agenda-remove-tags t)
|
|
(org-agenda-add-entry-text-maxlines 2)
|
|
(htmlize-output-type 'css))
|
|
(concat (file-name-as-directory (getenv "XDG_RUNTIME_DIR")) "org/agenda.html"))))
|
|
|
|
(setq org-tag-alist '(
|
|
(:startgroup . nil)
|
|
("@immersive" . ?i)
|
|
("@process" . ?p)
|
|
(:endgroup . nil)
|
|
(:startgroup . nil)
|
|
("@deep" . ?d)
|
|
("@shallow" . ?s)
|
|
(:endgroup . nil)
|
|
(:startgroup . nil)
|
|
("@office" . ?o)
|
|
("@home" . ?h)
|
|
(:endgroup . nil)
|
|
("errand" . ?E)
|
|
("phone" . ?P)
|
|
("outbox" . ?O)
|
|
("money" . ?M)
|
|
("paper" . ?P)
|
|
("next" . ?N)))
|
|
|
|
; Daily Review
|
|
(defun bascht/daily-review ()
|
|
(interactive)
|
|
(persp-switch "@Org")
|
|
(find-file "/home/bascht/Documents/Zettelkasten/Todo.org")
|
|
(goto-char (org-find-exact-headline-in-buffer "Daily Review"))
|
|
(org-narrow-to-subtree)
|
|
(org-cycle-hide-drawers 'all)
|
|
(search-forward "[ ]"))
|
|
|
|
(defun bascht/org-agenda ()
|
|
(interactive)
|
|
(persp-switch "@Org")
|
|
(let ((org-agenda-start-with-log-mode 'nil)
|
|
(org-agenda-show-log 'nil)
|
|
(org-agenda-span 'day)
|
|
(org-agenda-use-time-grid t))
|
|
(org-agenda nil "c")
|
|
(org-agenda-redo)
|
|
))
|
|
|
|
; Recent loops callable for daily review
|
|
(defun bascht/org-agenda-recent-open-loops ()
|
|
(interactive)
|
|
(let ((org-agenda-start-with-log-mode t)
|
|
(org-agenda-span 'day)
|
|
(org-agenda-use-time-grid nil))
|
|
(org-agenda nil "l")
|
|
(beginend-org-agenda-mode-goto-beginning)))
|
|
|
|
(defun bascht/sway-org-clock-indicator ()
|
|
(if (org-clocking-p)
|
|
(format "%s @ %s"
|
|
org-clock-heading
|
|
(format "%2f h" (/ (org-clock-get-clocked-time) 60.0)))
|
|
(format "🕶 chilling")))
|
|
|
|
(add-to-list 'org-global-properties
|
|
'("Effort_ALL". "0:05 0:10 0:15 0:30 1:00 2:00 3:00 4:00"))
|
|
|
|
; Via https://www.reddit.com/r/emacs/comments/8kz8dv/tip_how_i_use_orgjournal_to_improve_my/
|
|
(defun bascht/goto-yesterdays-journal ()
|
|
(interactive)
|
|
(find-file (expand-file-name (concat org-journal-dir (format-time-string "%Y%m%d" (time-subtract (current-time) (days-to-time 1)))))))
|
|
|
|
;; Find my work tree and clock into the respective day / create entry if it does not exist
|
|
(defun bascht/alfatraining-clock-in ()
|
|
(interactive)
|
|
(save-excursion
|
|
|
|
(find-file (expand-file-name "Alfaview.org" org-directory))
|
|
(goto-char (point-min))
|
|
|
|
(let ((month (format-time-string "%Y-%m"))
|
|
(today (format-time-string "[%Y-%m-%d]")))
|
|
(goto-char (org-find-exact-headline-in-buffer month))
|
|
|
|
(if (integer-or-marker-p (org-find-exact-headline-in-buffer today))
|
|
(goto-char (org-find-exact-headline-in-buffer today))
|
|
(progn
|
|
(org-insert-subheading nil)
|
|
(insert today)))
|
|
(org-clock-in)
|
|
(save-buffer))))
|
|
|
|
;; Add the a small button to report the current clock line in a :clockreport to
|
|
;; Personio. This won't actually do the remote call, but just add a elisp: hyperlink.
|
|
;; That way we keep the table rendering nice and quick.
|
|
;; Skip the first 3 total / sum rows by matching the current item against =org-ts-regexp0=
|
|
(defun bascht/ts-for-report-table (ts h)
|
|
(save-excursion
|
|
(if (string-match org-ts-regexp0 ts)
|
|
(progn
|
|
(beginning-of-buffer)
|
|
(goto-char (org-find-exact-headline-in-buffer ts))
|
|
(if (org-entry-get nil "PERSONIO_REPORTED")
|
|
"✓ Reported"
|
|
(progn
|
|
(search-forward ":LOGBOOK:")
|
|
(search-forward ":END:")
|
|
(forward-line -1)
|
|
(let* ((timestamp (org-element-property :value (org-element-at-point)))
|
|
(ts-start (org-timestamp-to-time timestamp))
|
|
(ts-end (org-timestamp-to-time timestamp t))
|
|
(hours (s-chop-suffix "h" h)))
|
|
|
|
(format "[[elisp:(bascht/ts-report-to-personio '%s %s)][Report]]" ts-start hours))
|
|
)))
|
|
"")))
|
|
|
|
; Split working hours into personio-compatible slots around a 1 hour break in
|
|
; case the report is longer than 4 hours. There are probably a 1000 easier
|
|
; ways to do this, but I'mma take proud in my hacky solution since it works
|
|
; and it was hard enough to cobble together.
|
|
(defun bascht/ts-report-to-personio (ts hours)
|
|
(point-to-register 'bascht/ts-report-current-table)
|
|
(async-start
|
|
(lambda ()
|
|
(if (> hours 4)
|
|
(let* ((first-shift-end (time-add ts (seconds-to-time (* 3600 4))))
|
|
(break-end (time-add first-shift-end 3600))
|
|
(shift-end (time-add break-end (seconds-to-time (* 3600 (- hours 4))))))
|
|
|
|
(shell-command (format "report-to-personio \"%s\" \"%s\" \"%s\" \"%s\""
|
|
(format-time-string "%R" ts)
|
|
(format-time-string "%R" first-shift-end)
|
|
(format-time-string "%R" break-end)
|
|
(format-time-string "%R" shift-end)))
|
|
)
|
|
|
|
(let* ((shift-end (time-add ts (seconds-to-time (* hours 3600)))))
|
|
(shell-command (format "report-to-personio \"%s\" \"%s\""
|
|
(format-time-string "%R" ts)
|
|
(format-time-string "%R" shift-end)))))
|
|
|
|
(list (format-time-string "[%F]" ts) (format "Successfully reported %s hours to Personio" hours)))
|
|
|
|
(lambda (result)
|
|
(jump-to-register 'bascht/ts-report-current-table)
|
|
(save-excursion
|
|
(beginning-of-buffer)
|
|
(goto-char (org-find-exact-headline-in-buffer (car-safe result)))
|
|
(org-set-property "PERSONIO_REPORTED" "t"))
|
|
(message (car-safe (cdr-safe result)))
|
|
(org-table-recalculate))))
|
|
|
|
(defun bascht/alfatraining-hours-a-day (date)
|
|
(cond
|
|
((string-match "Mon" (s-trim date)) 4)
|
|
((string-match "Tue" (s-trim date)) 8)
|
|
((string-match "Wed" (s-trim date)) 8)
|
|
((string-match "Thu" (s-trim date)) 8)
|
|
((string-match "Fri" (s-trim date)) 2)
|
|
(t "0:00")))
|
|
|
|
(defun bascht/send-org-clock-to-ulanzi ()
|
|
(if (org-clocking-p)
|
|
(let* ((clocked-time (/ (org-clock-get-clocked-time) 60.0))
|
|
(percent (round (*(/ clocked-time (bascht/alfatraining-hours-a-day (format-time-string "%a"))) 100)))
|
|
(text (format "%.1fh" clocked-time)))
|
|
|
|
(request "http://10.11.12.180/api/custom"
|
|
:type "POST"
|
|
:headers '(("Content-Type" . "application/json"))
|
|
:data (json-encode `(("name" . "worklog")
|
|
("icon" . "11402")
|
|
("progress" . ,percent)
|
|
("text" . ,text))))
|
|
)
|
|
|
|
))
|
|
|
|
(defun bascht/org-file-show-headings (org-file)
|
|
(interactive)
|
|
(find-file (expand-file-name org-file))
|
|
(counsel-org-goto)
|
|
(org-fold-show-subtree))
|
|
|
|
(defun bascht/wzzk-find ()
|
|
(interactive)
|
|
(projectile-find-file-in-directory bascht/wzzk))
|
|
|
|
(defun bascht/wzzk-find-today ()
|
|
(interactive)
|
|
(let ((journal-today (expand-file-name (format-time-string "journals/%Y-%m-%d.md") bascht/wzzk)))
|
|
(unless (file-exists-p journal-today)
|
|
(message (concat "No journal for today, creating " (concat journal-today "on the fly.")))
|
|
(copy-file (expand-file-name "journals/_template.md" bascht/wzzk) journal-today))
|
|
(find-file journal-today))
|
|
(beginning-of-buffer)
|
|
(replace-string "<% tp.file.creation_date() %>" (format-time-string "%Y-%m-%d %H:%m"))
|
|
(replace-string "DailyNote <% tp.file.title.split('-')[0] %>" (format-time-string "DailyNote %Y"))
|
|
(end-of-buffer))
|
|
|
|
(defun bascht/wzzk-find-yesterday ()
|
|
(interactive)
|
|
(find-file (expand-file-name
|
|
(format-time-string "%Y-%m-%d.md"
|
|
(time-subtract (current-time) (days-to-time 1))) "~/WirZwei/Zettelkasten/journals")))
|
|
|
|
|
|
(defun +mu4e/capture-msg-to-agenda (arg)
|
|
"Refile a message and add a entry in `+org-capture-emails-file' with a
|
|
deadline. Default deadline is today. With one prefix, deadline
|
|
is tomorrow. With two prefixes, select the deadline."
|
|
(interactive "p")
|
|
(let ((sec "^* Email")
|
|
(msg (mu4e-message-at-point)))
|
|
(when msg
|
|
;; put the message in the agenda
|
|
(with-current-buffer (find-file-noselect
|
|
(expand-file-name +org-capture-emails-file org-directory))
|
|
(save-excursion
|
|
;; find header section
|
|
(goto-char (point-max))
|
|
(let (org-M-RET-may-split-line
|
|
(lev (org-outline-level))
|
|
(folded-p (invisible-p (point-at-eol)))
|
|
(from (plist-get msg :from)))
|
|
(when (consp (car from)) ; Occurs when using mu4e 1.8+.
|
|
(setq from (car from)))
|
|
;;
|
|
;; place the subheader
|
|
(org-end-of-meta-data) ; skip property drawer
|
|
(org-insert-todo-heading 1) ; insert a todo heading
|
|
;;
|
|
;; insert message and add deadline
|
|
(insert (concat "Email beantworten: "
|
|
"[[mu4e:msgid:"
|
|
(plist-get msg :message-id) "]["
|
|
(truncate-string-to-width
|
|
(plist-get from :name) 25 nil nil t)
|
|
" - "
|
|
(truncate-string-to-width
|
|
(plist-get msg :subject) 40 nil nil t)
|
|
"]] :email:"))
|
|
(org-deadline nil
|
|
(cond ((= arg 1) (format-time-string "%Y-%m-%d"))
|
|
((= arg 4) "+1d")))
|
|
|
|
(org-update-parent-todo-statistics)
|
|
|
|
;; refold as necessary
|
|
(if folded-p
|
|
(progn
|
|
(org-up-heading-safe)
|
|
(hide-subtree))
|
|
(hide-entry)))))
|
|
;; refile the message and update
|
|
(cond ((eq major-mode 'mu4e-view-mode)
|
|
(mu4e-view-mark-for-refile))
|
|
((eq major-mode 'mu4e-headers-mode)
|
|
(mu4e-headers-mark-for-refile)))
|
|
(message "Refiled \"%s\" and added to the agenda for %s"
|
|
(truncate-string-to-width
|
|
(plist-get msg :subject) 40 nil nil t)
|
|
(cond ((= arg 1) "today")
|
|
((= arg 4) "tomorrow")
|
|
(t "later"))))))
|
|
|
|
(setq org-agenda-category-icon-alist
|
|
'(("Todo" "~/.icons/emacs/todo-16x16.png" nil nil :ascent center)
|
|
("Personal" "~/.icons/emacs/person-16x16.png" nil nil :ascent center)
|
|
("Customer.*" "~/.icons/emacs/customer-16x16.png" nil nil :ascent center)
|
|
("Alfaview" "~/.icons/emacs/customer-16x16.png" nil nil :ascent center)
|
|
("Calendar" "~/.icons/emacs/calendar-16x16.png" nil nil :ascent center)
|
|
("Freelance.*" "~/.icons/emacs/customer-16x16.png" nil nil :ascent center)
|
|
("Projects" "~/.icons/emacs/generic-folder-16x16.png" nil nil :ascent center)
|
|
("\\(ROPrivat\\|ROArbeit\\)" "~/.icons/emacs/calendar-16x16.png" nil nil :ascent center)
|
|
(".*" '(space . (:width (16))))))
|
|
|
|
; Save file on every state change
|
|
(add-hook 'org-trigger-hook 'save-buffer)
|
|
(add-hook 'org-clock-in-hook 'save-buffer)
|
|
(add-hook 'org-clock-out-hook 'save-buffer))
|
|
|
|
(use-package! literate-calc-mode)
|
|
|
|
(use-package! org-journal
|
|
:after (org)
|
|
:init
|
|
(if (string= (getenv "EMACS_SERVER_NAME") "workmacs")
|
|
(progn
|
|
(run-hooks 'doom-first-input-hook)
|
|
(setq writeroom-width 90)
|
|
(setq indicate-empty-lines nil)
|
|
(spacious-padding-mode)
|
|
(global-hide-mode-line-mode)
|
|
(ef-themes-select 'ef-cyprus)
|
|
(add-hook 'org-journal-mode-hook
|
|
(lambda () (add-hook 'after-save-hook 'delete-frame)))
|
|
; Somehow my brain mapped this shortcut in org-journal mode
|
|
; Oh yes, you know why? Because they feel like I finish a "git commit" :D
|
|
(map! :after org-journal
|
|
:map org-journal-mode-map
|
|
:n "C-c C-c" #'save-buffer)
|
|
(setq server-client-instructions nil) ;; hide noisy minibuffer
|
|
(org-journal-open-current-journal-file)))
|
|
:config
|
|
(setq org-journal-dir "~/Documents/Worklog/"
|
|
org-journal-enable-agenda-integration nil
|
|
org-journal-file-format "%Y%m%d"
|
|
org-journal-date-format "%A, %d/%m/%Y"
|
|
org-journal-carryover-items nil))
|
|
|
|
(use-package! khalel
|
|
:after org
|
|
:config
|
|
(setq khalel-import-org-file (expand-file-name "Calendar.org" org-directory))
|
|
(setq khalel-import-end-date "+14d")
|
|
(setq khalel-import-org-file-confirm-overwrite nil)
|
|
(khalel-add-capture-template))
|
|
|
|
(use-package! org-habit
|
|
:init
|
|
(setq
|
|
org-habit-graph-column 1
|
|
org-habit-preceding-days 10
|
|
org-habit-following-days 1
|
|
org-habit-show-habits-only-for-today nil))
|