2017-12-03 09:19:05 +01:00
|
|
|
|
;;; org.el -- Daniel's org mode configuration -*- lexical-binding: t -*-
|
2017-07-16 18:07:00 +02:00
|
|
|
|
|
|
|
|
|
;;; Commentary:
|
|
|
|
|
|
2018-11-03 11:38:42 +01:00
|
|
|
|
;; This file defines functions used in the main configuration of org-mode and
|
|
|
|
|
;; it’s subpackages. Nothing here changes the behavior of org-mode per se, as
|
|
|
|
|
;; loading this file only defines a couple of functions.
|
2018-01-21 18:12:48 +01:00
|
|
|
|
|
2017-07-16 18:07:00 +02:00
|
|
|
|
;;; Code:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
;;; Agenda Customization
|
|
|
|
|
|
2018-11-03 10:59:41 +01:00
|
|
|
|
;; For customization of default org agenda files
|
2017-10-27 21:14:26 +02:00
|
|
|
|
(defun db/update-org-agenda-files (symbol value)
|
2019-02-09 17:39:12 +01:00
|
|
|
|
"Set SYMBOL to VALUE and update `org-agenda-files’ afterwards.
|
|
|
|
|
Remove the old value of SYMBOL from `org-agenda-files’ and add
|
|
|
|
|
the new one instead."
|
2020-01-05 11:56:05 +01:00
|
|
|
|
(when (and (boundp symbol)
|
|
|
|
|
(symbol-value symbol))
|
|
|
|
|
(require 'org)
|
|
|
|
|
(org-remove-file (symbol-value symbol)))
|
2017-10-27 21:14:26 +02:00
|
|
|
|
(set-default symbol value)
|
2020-01-05 11:56:05 +01:00
|
|
|
|
(when value
|
|
|
|
|
(if (not (and (stringp value)
|
|
|
|
|
(file-exists-p value)
|
|
|
|
|
(file-readable-p value)))
|
|
|
|
|
(user-error "File %s does not exist or is not readable; not setting %s."
|
|
|
|
|
value symbol)
|
2020-01-05 12:10:31 +01:00
|
|
|
|
|
|
|
|
|
;; this is essentially `org-agenda-file-to-front', but using `value'
|
|
|
|
|
;; instead of `buffer-file-name'
|
2020-01-05 11:56:05 +01:00
|
|
|
|
(require 'org)
|
2020-01-05 12:10:31 +01:00
|
|
|
|
(let ((org-agenda-skip-unavailable-files nil)
|
|
|
|
|
(file-alist (mapcar (lambda (x)
|
|
|
|
|
(cons (file-truename x) x))
|
|
|
|
|
(org-agenda-files t)))
|
|
|
|
|
(ctf (file-truename value))
|
|
|
|
|
x had)
|
|
|
|
|
(setq x (assoc ctf file-alist) had x)
|
|
|
|
|
|
|
|
|
|
(unless x
|
2020-01-05 12:17:37 +01:00
|
|
|
|
(setq x (cons ctf (abbreviate-file-name value))))
|
2020-01-05 12:10:31 +01:00
|
|
|
|
(setq file-alist (append (delq x file-alist) (list x)))
|
|
|
|
|
(org-store-new-agenda-file-list (mapcar 'cdr file-alist))
|
|
|
|
|
(org-install-agenda-files-menu)
|
|
|
|
|
(message "File %s to %s of agenda file list"
|
|
|
|
|
(if had "moved" "added") "end")))))
|
2017-10-27 21:14:26 +02:00
|
|
|
|
|
2017-07-16 18:07:00 +02:00
|
|
|
|
(defun db/org-agenda-list-deadlines (&optional match)
|
|
|
|
|
;; XXX org-agenda-later does not work, fix this
|
|
|
|
|
"Prepare agenda view that only lists upcoming deadlines.
|
|
|
|
|
|
|
|
|
|
Ignores MATCH."
|
|
|
|
|
(interactive "P")
|
|
|
|
|
(catch 'exit
|
|
|
|
|
(org-agenda-prepare "Deadlines")
|
|
|
|
|
(org-compile-prefix-format 'agenda)
|
|
|
|
|
(org-set-sorting-strategy 'agenda)
|
|
|
|
|
|
|
|
|
|
(let* ((today (org-today))
|
|
|
|
|
(thefiles (org-agenda-files nil 'ifmode))
|
|
|
|
|
(inhibit-redisplay (not debug-on-error))
|
2018-01-16 17:55:15 +01:00
|
|
|
|
s rtn rtnall file files date start-pos)
|
2017-07-16 18:07:00 +02:00
|
|
|
|
|
|
|
|
|
;; headline
|
|
|
|
|
(unless org-agenda-compact-blocks
|
|
|
|
|
(setq s (point))
|
|
|
|
|
(if org-agenda-overriding-header
|
|
|
|
|
(insert (org-add-props (copy-sequence org-agenda-overriding-header)
|
|
|
|
|
nil 'face 'org-agenda-structure) "\n"))
|
|
|
|
|
(org-agenda-mark-header-line s))
|
|
|
|
|
|
|
|
|
|
;; actual content
|
|
|
|
|
(setq date (calendar-gregorian-from-absolute today)
|
|
|
|
|
s (point)
|
|
|
|
|
start-pos (point)
|
|
|
|
|
files thefiles
|
|
|
|
|
rtnall nil)
|
|
|
|
|
(while (setq file (pop files))
|
|
|
|
|
(catch 'nextfile
|
|
|
|
|
(org-check-agenda-file file)
|
|
|
|
|
(setq rtn (apply 'org-agenda-get-day-entries
|
|
|
|
|
file date
|
|
|
|
|
'(:deadline)))
|
|
|
|
|
(setq rtnall (append rtnall rtn)))) ;; all entries
|
|
|
|
|
(when rtnall
|
|
|
|
|
(insert (org-agenda-finalize-entries rtnall 'agenda)
|
|
|
|
|
"\n"))
|
|
|
|
|
|
|
|
|
|
;; finalize
|
|
|
|
|
(goto-char (point-min))
|
|
|
|
|
(or org-agenda-multi (org-agenda-fit-window-to-buffer))
|
|
|
|
|
(unless (and (pos-visible-in-window-p (point-min))
|
|
|
|
|
(pos-visible-in-window-p (point-max)))
|
|
|
|
|
(goto-char (1- (point-max)))
|
|
|
|
|
(recenter -1)
|
|
|
|
|
(if (not (pos-visible-in-window-p (or start-pos 1)))
|
|
|
|
|
(progn
|
|
|
|
|
(goto-char (or start-pos 1))
|
|
|
|
|
(recenter 1))))
|
|
|
|
|
(goto-char (or start-pos 1))
|
|
|
|
|
(add-text-properties
|
|
|
|
|
(point-min) (point-max)
|
|
|
|
|
`(org-agenda-type agenda
|
|
|
|
|
org-redo-cmd
|
|
|
|
|
(db/org-agenda-list-deadlines ,match)))
|
|
|
|
|
(org-agenda-finalize)
|
|
|
|
|
(setq buffer-read-only t)
|
|
|
|
|
(message ""))))
|
|
|
|
|
|
|
|
|
|
(defun db/org-agenda-skip-tag (tag &optional others)
|
|
|
|
|
;; https://stackoverflow.com/questions/10074016/org-mode-filter-on-tag-in-agenda-view
|
|
|
|
|
"Skip all entries that correspond to TAG.
|
|
|
|
|
|
|
|
|
|
If OTHERS is true, skip all entries that do not correspond to TAG."
|
|
|
|
|
(let* ((next-headline (save-mark-and-excursion
|
|
|
|
|
(or (outline-next-heading) (point-max))))
|
|
|
|
|
(current-headline (or (and (org-at-heading-p)
|
|
|
|
|
(point))
|
|
|
|
|
(save-mark-and-excursion
|
|
|
|
|
;; remember to also consider invisible headings
|
|
|
|
|
(org-back-to-heading t))))
|
|
|
|
|
(has-tag (member tag (org-get-tags-at current-headline))))
|
|
|
|
|
(if (or (and others (not has-tag))
|
|
|
|
|
(and (not others) has-tag))
|
|
|
|
|
next-headline
|
|
|
|
|
nil)))
|
|
|
|
|
|
|
|
|
|
(defun db/cmp-date-property (prop)
|
|
|
|
|
;; https://emacs.stackexchange.com/questions/26351/custom-sorting-for-agenda
|
|
|
|
|
"Compare two `org-mode' agenda entries, `A' and `B', by some date property.
|
|
|
|
|
|
|
|
|
|
If a is before b, return -1. If a is after b, return 1. If they
|
|
|
|
|
are equal return nil."
|
|
|
|
|
(lexical-let ((prop prop))
|
|
|
|
|
#'(lambda (a b)
|
|
|
|
|
(let* ((a-pos (get-text-property 0 'org-marker a))
|
|
|
|
|
(b-pos (get-text-property 0 'org-marker b))
|
|
|
|
|
(a-date (or (org-entry-get a-pos prop)
|
|
|
|
|
(format "<%s>" (org-read-date t nil "now"))))
|
|
|
|
|
(b-date (or (org-entry-get b-pos prop)
|
|
|
|
|
(format "<%s>" (org-read-date t nil "now"))))
|
|
|
|
|
(cmp (compare-strings a-date nil nil b-date nil nil)))
|
2018-01-16 17:55:15 +01:00
|
|
|
|
(if (eq cmp t) nil (cl-signum cmp))))))
|
2017-07-16 18:07:00 +02:00
|
|
|
|
|
|
|
|
|
;; A Hydra for changing agenda appearance
|
|
|
|
|
;; http://oremacs.com/2016/04/04/hydra-doc-syntax/
|
|
|
|
|
|
|
|
|
|
(defun db/org-agenda-span ()
|
|
|
|
|
"Return the display span of the current shown agenda."
|
|
|
|
|
(let ((args (get-text-property
|
|
|
|
|
(min (1- (point-max)) (point))
|
|
|
|
|
'org-last-args)))
|
|
|
|
|
(nth 2 args)))
|
|
|
|
|
|
|
|
|
|
(defhydra hydra-org-agenda-view (:hint none)
|
|
|
|
|
"
|
|
|
|
|
_d_: ?d? day _g_: time grid=?g? _a_: arch-trees
|
|
|
|
|
_w_: ?w? week _[_: inactive _A_: arch-files
|
|
|
|
|
_t_: ?t? fortnight _F_: follow=?F? _r_: report=?r?
|
|
|
|
|
_m_: ?m? month _e_: entry =?e? _D_: diary=?D?
|
|
|
|
|
_y_: ?y? year _q_: quit _L__l__c_: ?l?
|
|
|
|
|
|
|
|
|
|
"
|
|
|
|
|
("SPC" org-agenda-reset-view)
|
|
|
|
|
("d" org-agenda-day-view
|
|
|
|
|
(if (eq 'day (db/org-agenda-span))
|
|
|
|
|
"[x]" "[ ]"))
|
|
|
|
|
("w" org-agenda-week-view
|
|
|
|
|
(if (eq 'week (db/org-agenda-span))
|
|
|
|
|
"[x]" "[ ]"))
|
|
|
|
|
("t" org-agenda-fortnight-view
|
|
|
|
|
(if (eq 'fortnight (db/org-agenda-span))
|
|
|
|
|
"[x]" "[ ]"))
|
|
|
|
|
("m" org-agenda-month-view
|
|
|
|
|
(if (eq 'month (db/org-agenda-span)) "[x]" "[ ]"))
|
|
|
|
|
("y" org-agenda-year-view
|
|
|
|
|
(if (eq 'year (db/org-agenda-span)) "[x]" "[ ]"))
|
|
|
|
|
("l" org-agenda-log-mode
|
|
|
|
|
(format "% -3S" org-agenda-show-log))
|
|
|
|
|
("L" (org-agenda-log-mode '(4)))
|
|
|
|
|
("c" (org-agenda-log-mode 'clockcheck))
|
|
|
|
|
("F" org-agenda-follow-mode
|
|
|
|
|
(format "% -3S" org-agenda-follow-mode))
|
|
|
|
|
("a" org-agenda-archives-mode)
|
|
|
|
|
("A" (org-agenda-archives-mode 'files))
|
|
|
|
|
("r" org-agenda-clockreport-mode
|
|
|
|
|
(format "% -3S" org-agenda-clockreport-mode))
|
|
|
|
|
("e" org-agenda-entry-text-mode
|
|
|
|
|
(format "% -3S" org-agenda-entry-text-mode))
|
|
|
|
|
("g" org-agenda-toggle-time-grid
|
|
|
|
|
(format "% -3S" org-agenda-use-time-grid))
|
|
|
|
|
("D" org-agenda-toggle-diary
|
|
|
|
|
(format "% -3S" org-agenda-include-diary))
|
|
|
|
|
("!" org-agenda-toggle-deadlines)
|
|
|
|
|
("["
|
|
|
|
|
(let ((org-agenda-include-inactive-timestamps t))
|
|
|
|
|
(org-agenda-check-type t 'timeline 'agenda)
|
|
|
|
|
(org-agenda-redo)))
|
|
|
|
|
("q" (message "Abort") :exit t))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
;;; Capturing
|
|
|
|
|
|
2017-07-18 18:14:53 +02:00
|
|
|
|
(defun db/org-timestamp-difference (stamp-1 stamp-2)
|
|
|
|
|
"Returns time difference between two given org-mode timestamps."
|
|
|
|
|
;; Things copied from `org-clock-update-time-maybe’
|
|
|
|
|
(let* ((s (-
|
|
|
|
|
(float-time
|
2018-01-16 17:55:15 +01:00
|
|
|
|
(apply #'encode-time (org-parse-time-string stamp-2 t)))
|
2017-07-18 18:14:53 +02:00
|
|
|
|
(float-time
|
2018-01-16 17:55:15 +01:00
|
|
|
|
(apply #'encode-time (org-parse-time-string stamp-1 t)))))
|
2017-07-18 18:14:53 +02:00
|
|
|
|
(neg (< s 0))
|
|
|
|
|
(s (abs s))
|
|
|
|
|
(h (floor (/ s 3600)))
|
|
|
|
|
(m (floor (/ (- s (* 3600 h)) 60))))
|
|
|
|
|
(format (if neg "-%d:%02d" "%2d:%02d") h m)))
|
|
|
|
|
|
2018-08-18 16:18:14 +02:00
|
|
|
|
;; Capture Code Snippets
|
|
|
|
|
;; from http://ul.io/nb/2018/04/30/better-code-snippets-with-org-capture/
|
|
|
|
|
(defun db/org-capture-code-snippet (filename)
|
2018-08-18 16:32:30 +02:00
|
|
|
|
"Format Org mode entry for capturing code in active region in
|
|
|
|
|
the buffer visiting FILENAME."
|
2018-08-18 16:18:14 +02:00
|
|
|
|
(with-current-buffer (find-buffer-visiting filename)
|
|
|
|
|
(let ((code-snippet (buffer-substring-no-properties (mark) (- (point) 1)))
|
|
|
|
|
(func-name (which-function))
|
|
|
|
|
(file-name (buffer-file-name))
|
|
|
|
|
(line-number (line-number-at-pos (region-beginning)))
|
|
|
|
|
(org-src-mode (let ((mm (intern (replace-regexp-in-string
|
|
|
|
|
"-mode" "" (format "%s" major-mode)))))
|
|
|
|
|
(or (car (rassoc mm org-src-lang-modes))
|
|
|
|
|
(format "%s" mm)))))
|
|
|
|
|
(format
|
|
|
|
|
"file:%s::%s
|
|
|
|
|
In ~%s~:
|
|
|
|
|
#+BEGIN_SRC %s
|
|
|
|
|
%s
|
|
|
|
|
#+END_SRC"
|
|
|
|
|
file-name
|
|
|
|
|
line-number
|
|
|
|
|
func-name
|
|
|
|
|
org-src-mode
|
|
|
|
|
code-snippet))))
|
|
|
|
|
|
2018-11-18 16:39:43 +01:00
|
|
|
|
;; Make capture frame, made for being called via emacsclient
|
|
|
|
|
;; https://cestlaz.github.io/posts/using-emacs-24-capture-2/
|
|
|
|
|
|
|
|
|
|
(defun db/make-org-capture-frame ()
|
|
|
|
|
"Create a new frame for capturing."
|
|
|
|
|
(interactive)
|
|
|
|
|
(make-frame '((name . "capture")))
|
|
|
|
|
(select-frame-by-name "capture")
|
|
|
|
|
(delete-other-windows)
|
2018-11-18 16:57:16 +01:00
|
|
|
|
(org-capture))
|
2018-11-18 16:39:43 +01:00
|
|
|
|
|
|
|
|
|
(defun db/delete-frame-if-capture (&rest r)
|
|
|
|
|
"If current frame was made for a capture, close after done."
|
|
|
|
|
(ignore r)
|
|
|
|
|
(when (equal (frame-parameter nil 'name)
|
|
|
|
|
"capture")
|
|
|
|
|
(delete-frame)))
|
|
|
|
|
|
|
|
|
|
(advice-add 'org-capture-finalize
|
|
|
|
|
:after #'db/delete-frame-if-capture)
|
|
|
|
|
|
2017-07-16 18:07:00 +02:00
|
|
|
|
|
|
|
|
|
;;; Refiling
|
|
|
|
|
|
2018-11-03 11:15:20 +01:00
|
|
|
|
;; Exclude DONE state tasks from refile targets (from bh)
|
2018-02-14 22:06:42 +01:00
|
|
|
|
(defun db/verify-refile-target ()
|
|
|
|
|
"Exclude todo keywords with a done state from refile targets"
|
2018-11-03 09:45:09 +01:00
|
|
|
|
(not (member (nth 2 (org-heading-components))
|
|
|
|
|
org-done-keywords)))
|
2018-02-14 22:06:42 +01:00
|
|
|
|
|
2017-07-16 18:07:00 +02:00
|
|
|
|
|
2017-08-12 11:25:04 +02:00
|
|
|
|
;;; Reset checklists
|
2017-07-16 18:07:00 +02:00
|
|
|
|
|
2017-08-12 11:25:04 +02:00
|
|
|
|
;; from `org-checklist’ by James TD Smith (@ ahktenzero (. mohorovi cc)),
|
|
|
|
|
;; version: 1.0
|
|
|
|
|
(defun org-reset-checkbox-state-maybe ()
|
|
|
|
|
"Reset all checkboxes in an entry if the `RESET_CHECK_BOXES' property is set"
|
|
|
|
|
(interactive "*")
|
|
|
|
|
(if (org-entry-get (point) "RESET_CHECK_BOXES")
|
|
|
|
|
(org-reset-checkbox-state-subtree)))
|
|
|
|
|
|
2018-11-03 10:28:49 +01:00
|
|
|
|
|
2019-08-31 11:26:04 +02:00
|
|
|
|
;;; Helper Functions for Clocking
|
2018-11-03 10:28:49 +01:00
|
|
|
|
|
|
|
|
|
(defun db/find-parent-task ()
|
|
|
|
|
;; http://doc.norang.ca/org-mode.html#Clocking
|
|
|
|
|
"Return point of the nearest parent task, and NIL if no such task exists."
|
|
|
|
|
(save-mark-and-excursion
|
|
|
|
|
(save-restriction
|
|
|
|
|
(widen)
|
|
|
|
|
(let ((parent-task nil))
|
|
|
|
|
(or (org-at-heading-p)
|
|
|
|
|
(org-back-to-heading t))
|
|
|
|
|
(while (and (not parent-task)
|
|
|
|
|
(org-up-heading-safe))
|
|
|
|
|
(let ((tags (nth 5 (org-heading-components))))
|
|
|
|
|
(unless (and tags (member "NOP" (split-string tags ":" t)))
|
|
|
|
|
(setq parent-task (point)))))
|
|
|
|
|
parent-task))))
|
|
|
|
|
|
|
|
|
|
(defun db/ensure-running-clock ()
|
|
|
|
|
"Clocks in into the parent task, if it exists, or the default task."
|
|
|
|
|
(when (and (not org-clock-clocking-in)
|
|
|
|
|
(not org-clock-resolving-clocks-due-to-idleness))
|
|
|
|
|
(let ((parent-task (db/find-parent-task)))
|
|
|
|
|
(save-mark-and-excursion
|
|
|
|
|
(cond
|
|
|
|
|
(parent-task
|
|
|
|
|
;; found parent task
|
|
|
|
|
(org-with-point-at parent-task
|
|
|
|
|
(org-clock-in)))
|
|
|
|
|
((and (markerp org-clock-default-task)
|
|
|
|
|
(marker-buffer org-clock-default-task))
|
|
|
|
|
;; default task is set
|
|
|
|
|
(org-with-point-at org-clock-default-task
|
|
|
|
|
(org-clock-in)))
|
|
|
|
|
(t
|
|
|
|
|
(org-clock-in '(4))))))))
|
|
|
|
|
|
2018-11-03 10:30:47 +01:00
|
|
|
|
(defun db/save-current-org-task-to-file ()
|
2018-11-03 10:28:49 +01:00
|
|
|
|
"Format currently clocked task and write it to
|
|
|
|
|
`db/org-clock-current-task-file'."
|
|
|
|
|
(with-temp-file db/org-clock-current-task-file
|
|
|
|
|
(let ((clock-buffer (marker-buffer org-clock-marker)))
|
|
|
|
|
(if (null clock-buffer)
|
|
|
|
|
(insert "No running clock")
|
|
|
|
|
(insert org-clock-heading)))))
|
|
|
|
|
|
2019-08-31 11:26:04 +02:00
|
|
|
|
(defun db/org-update-frame-title-with-current-clock ()
|
2019-12-05 17:09:49 +01:00
|
|
|
|
"Set the title of all active frames to the headline of the
|
2019-08-31 11:26:04 +02:00
|
|
|
|
current task."
|
|
|
|
|
(interactive)
|
|
|
|
|
(let ((clock-buffer (marker-buffer org-clock-marker)))
|
|
|
|
|
(when clock-buffer
|
2019-12-05 17:09:49 +01:00
|
|
|
|
(dolist (frame (frame-list))
|
|
|
|
|
(modify-frame-parameters frame `((name . , org-clock-heading)))))))
|
2019-08-31 11:26:04 +02:00
|
|
|
|
|
2017-07-16 18:07:00 +02:00
|
|
|
|
|
|
|
|
|
;;; Fixes
|
|
|
|
|
|
|
|
|
|
(defun endless/org-ispell ()
|
|
|
|
|
"Configure `ispell-skip-region-alist' for `org-mode'."
|
|
|
|
|
(make-local-variable 'ispell-skip-region-alist)
|
|
|
|
|
(add-to-list 'ispell-skip-region-alist '(org-property-drawer-re))
|
|
|
|
|
(add-to-list 'ispell-skip-region-alist '("~" "~"))
|
|
|
|
|
(add-to-list 'ispell-skip-region-alist '("=" "="))
|
|
|
|
|
(add-to-list 'ispell-skip-region-alist '("^#\\+BEGIN_SRC" . "^#\\+END_SRC")))
|
|
|
|
|
|
2018-11-03 09:05:01 +01:00
|
|
|
|
|
|
|
|
|
;;; Hydra
|
|
|
|
|
|
2018-11-03 09:38:35 +01:00
|
|
|
|
(defun db/clock-in-task-by-id (task-id)
|
|
|
|
|
"Clock in org mode task as given by TASK-ID."
|
2018-11-18 16:00:13 +01:00
|
|
|
|
(let ((location (org-id-find task-id 'marker)))
|
|
|
|
|
(if (null location)
|
|
|
|
|
(user-error "Invalid location «%s» given." task-id)
|
|
|
|
|
(org-with-point-at location
|
|
|
|
|
(org-clock-in))
|
|
|
|
|
(org-save-all-org-buffers))))
|
2018-11-03 09:38:35 +01:00
|
|
|
|
|
|
|
|
|
(defun db/clock-out-task-by-id (task-id)
|
|
|
|
|
"Clock out org mode task as given by TASK-ID."
|
|
|
|
|
(org-with-point-at (org-id-find task-id 'marker)
|
|
|
|
|
(org-clock-out))
|
|
|
|
|
(org-save-all-org-buffers))
|
|
|
|
|
|
2018-11-18 16:00:04 +01:00
|
|
|
|
(defun db/org-clock-out ()
|
|
|
|
|
"Clock out current clock."
|
|
|
|
|
(interactive)
|
|
|
|
|
(org-clock-out))
|
|
|
|
|
|
|
|
|
|
(defun db/org-clock-in-break-task ()
|
|
|
|
|
"Clock into default break task as given by `org-break-task-id’."
|
|
|
|
|
(interactive)
|
|
|
|
|
(db/clock-in-task-by-id org-break-task-id))
|
|
|
|
|
|
|
|
|
|
(defun db/org-clock-in-home-task ()
|
|
|
|
|
"Clock into default home task as given by `org-home-task-id’."
|
|
|
|
|
(interactive)
|
|
|
|
|
(db/clock-in-task-by-id org-home-task-id))
|
|
|
|
|
|
|
|
|
|
(defun db/org-clock-in-work-task ()
|
|
|
|
|
"Clock into default work task as given by `org-work-task-id’."
|
|
|
|
|
(interactive)
|
|
|
|
|
(db/clock-in-task-by-id org-working-task-id))
|
|
|
|
|
|
2018-11-03 09:38:35 +01:00
|
|
|
|
(defun db/org-clock-in-last-task (&optional arg)
|
|
|
|
|
;; from doc.norang.ca, originally bh/clock-in-last-task
|
|
|
|
|
"Clock in the interrupted task if there is one.
|
|
|
|
|
|
|
|
|
|
Skip the default task and get the next one. If ARG is given,
|
|
|
|
|
forces clocking in of the default task."
|
|
|
|
|
(interactive "p")
|
|
|
|
|
(let ((clock-in-to-task
|
|
|
|
|
(cond
|
|
|
|
|
((eq arg 4) org-clock-default-task)
|
|
|
|
|
((and (org-clock-is-active)
|
|
|
|
|
(equal org-clock-default-task (cadr org-clock-history)))
|
|
|
|
|
(caddr org-clock-history))
|
|
|
|
|
((org-clock-is-active) (cadr org-clock-history))
|
|
|
|
|
((equal org-clock-default-task (car org-clock-history))
|
|
|
|
|
(cadr org-clock-history))
|
|
|
|
|
(t (car org-clock-history)))))
|
|
|
|
|
(widen)
|
|
|
|
|
(org-with-point-at clock-in-to-task
|
|
|
|
|
(org-clock-in nil))))
|
|
|
|
|
|
2018-11-03 11:31:36 +01:00
|
|
|
|
(defun db/org-clock-current-task ()
|
|
|
|
|
"Return currently clocked in task."
|
|
|
|
|
(require 'org-clock)
|
|
|
|
|
org-clock-current-task)
|
|
|
|
|
|
2018-11-03 09:05:01 +01:00
|
|
|
|
(defhydra hydra-org-clock (:color blue)
|
|
|
|
|
"
|
2018-11-03 11:31:36 +01:00
|
|
|
|
Current Task: %s(db/org-clock-current-task); "
|
2019-12-20 15:16:53 +01:00
|
|
|
|
("w" (db/org-clock-in-work-task) "work")
|
|
|
|
|
("h" (db/org-clock-in-home-task) "home")
|
|
|
|
|
("b" (db/org-clock-in-break-task) "break")
|
2018-11-03 09:05:01 +01:00
|
|
|
|
("i" (lambda ()
|
|
|
|
|
(interactive)
|
2019-12-20 15:16:53 +01:00
|
|
|
|
(org-clock-in '(4))) "interactive")
|
|
|
|
|
("a" counsel-org-goto-all "goto")
|
|
|
|
|
("o" org-clock-out "clock out")
|
|
|
|
|
("l" db/org-clock-in-last-task "last")
|
2018-11-03 09:05:01 +01:00
|
|
|
|
("d" (lambda ()
|
|
|
|
|
(interactive)
|
|
|
|
|
(when (org-clock-is-active)
|
|
|
|
|
(save-window-excursion
|
|
|
|
|
(org-clock-goto)
|
|
|
|
|
(let ((org-inhibit-logging 'note))
|
|
|
|
|
(org-todo 'done)
|
2019-12-20 15:16:53 +01:00
|
|
|
|
(org-save-all-org-buffers)))))
|
|
|
|
|
"default"))
|
2018-11-03 09:05:01 +01:00
|
|
|
|
|
2018-08-04 12:32:54 +02:00
|
|
|
|
|
|
|
|
|
;;; Babel
|
|
|
|
|
|
|
|
|
|
(defun org-babel-execute:hy (body params)
|
|
|
|
|
;; http://kitchingroup.cheme.cmu.edu/blog/2016/03/30/OMG-A-Lisp-that-runs-python/
|
|
|
|
|
"Execute hy code BODY with parameters PARAMS."
|
|
|
|
|
(ignore params)
|
|
|
|
|
(let* ((temporary-file-directory ".")
|
|
|
|
|
(tempfile (make-temp-file "hy-")))
|
|
|
|
|
(with-temp-file tempfile
|
|
|
|
|
(insert body))
|
|
|
|
|
(unwind-protect
|
|
|
|
|
(shell-command-to-string
|
|
|
|
|
(format "hy %s" tempfile))
|
|
|
|
|
(delete-file tempfile))))
|
|
|
|
|
|
2017-12-02 20:00:58 +01:00
|
|
|
|
|
2017-07-16 18:07:00 +02:00
|
|
|
|
;;; End
|
|
|
|
|
|
|
|
|
|
(provide 'db-org)
|
|
|
|
|
|
|
|
|
|
;;; db-org.el ends here
|