added orgmode conflict detection algorithm

This commit is contained in:
ndwarshuis 2018-11-22 23:56:59 -05:00
parent d7fcf4e24d
commit 12ff47da89
1 changed files with 102 additions and 0 deletions

102
conf.org
View File

@ -1122,6 +1122,108 @@ Clocking is still new and experimental (I'm not a ninja like Bernt yet). I mostl
org-clock-persist t
org-clock-report-include-clocking-task t)
#+END_SRC
*** conflict detection
Somehow org-mode has no way to detect conflicts between tasks with timestamps (!!??). Luckily I can make my own.
Steps for this algorithm:
1. make a list of all entries with timestamps
2. sort timestamp list
3. Walk through list and compare entries immediately after (sorting ensures that entries can be skipped once one non-conflict is found). If conflicts are found make a new list of each conflict pair.
4. Display conflicts in buffer
This should be O(n) (best case/no conflicts) to O(n^2) (worst case/everything conflicts)
#+BEGIN_SRC emacs-lisp
(defun nd/are-conflicting-p (ts-a ts-b)
"Return t if timestamps TS-A and TS-B conflict."
(let* ((earlier-a (car ts-a))
(earlier-b (car ts-b))
(later-b (+ earlier-b (nth 1 ts-b))))
(and (>= earlier-a earlier-b) (<= earlier-a later-b))))
(defun nd/detect-conflict (ts ts-list conlist)
"Recursively determine if timestamp TS conflicts with anything in TS-LIST.
If detected, conflict pair is added to CONLIST."
(let ((next-ts (car ts-list))
(rem-ts (cdr ts-list)))
(if (nd/are-conflicting-p ts next-ts)
(progn
(setq conlist (cons (list ts next-ts) conlist))
(if rem-ts (nd/detect-conflict ts rem-ts conlist) conlist))
conlist)))
(defun nd/build-conlist (ts-list conlist)
"Recursively build a list of timestamp conflicts from TS-LIST.
TS-LIST is comprised of entries in the form (staring-ts timerange marker)
where timerange is 0 for singular timestamps and a positive number for
anything with to times or a timestamp range.
Detected conflicts are stored in CONLIST as pairs of conflicting ts
entries from the TS-LIST."
(let ((cur-ts (car ts-list))
(rem-ts (cdr ts-list)))
(if rem-ts
(nd/build-conlist rem-ts (nd/detect-conflict cur-ts rem-ts conlist))
conlist)))
(defconst nd/org-tsm-regexp
"\\([0-9]\\{4\\}-[0-9]\\{2\\}-[0-9]\\{2\\} [^]+0-9>\r\n -]+? \\)\\([0-9]\\{1,2\\}:[0-9]\\{2\\}?\\)-\\([0-9]\\{1,2\\}:[0-9]\\{2\\}\\)"
"Regular expression for timestamps with two times.")
(defun nd/get-timestamps ()
"Get the org-marker and timestamp(s) (multiple if range) or current heading."
;; TODO, what if I care about more than just TIMESTAMPs
(let* ((ts (org-entry-get nil "TIMESTAMP"))
(marker (point-marker))
(ts-range 0)
(ts-entry))
(when ts
(cond
;; match timestamps that have two times
((string-match nd/org-tsm-regexp ts)
(let* ((ts1 (concat (match-string 1 ts) (match-string 2 ts)))
(ts2 (concat (match-string 1 ts) (match-string 3 ts)))
(ft1 (org-2ft ts1))
(ft2 (org-2ft ts2)))
(setq ts-entry ft1)
(setq ts-range (- ft2 ft1))))
;; match timestamps that have a range (eq two timestamps)
((string-match org-tr-regexp ts)
(let* ((ts1 (match-string 1 ts))
(ts2 (match-string 2 ts))
(ft1 (org-2ft ts1))
(ft2 (org-2ft ts2)))
(setq ts-entry ft1)
(setq ts-range (- ft2 ft1))))
;; match timestamps with only one time
(t (setq ts-entry (org-2ft ts))))
(list ts-entry ts-range marker))))
(defun nd/build-conflict-list ()
"Scan all org files and make a list of all timestamps that conflict."
(let ((files '("~/Org/reference/testconflict.org"))
prev-point ts-list cur-index conflicts)
;; get all timestamps from org buffers
(dolist (f files ts-list)
(with-current-buffer
(find-file-noselect f)
(goto-char (point-min))
(if (not (outline-on-heading-p)) (outline-next-heading))
(setq prev-point -1)
(while (> (point) prev-point)
(let ((new-ts (nd/get-timestamps)))
(if new-ts (setq ts-list (cons new-ts ts-list))))
(setq prev-point (point))
(outline-next-heading))))
;; sort the timestamp list
;; TODO, need to make range-aware
(setq ts-list (sort ts-list (lambda (a b) (< (car a) (car b)))))
;; build a list of conflicts
(nd/build-conlist ts-list conflicts)))
#+END_SRC
*** agenda
**** targets
The agenda files are limited to as few as possible to keep scanning and startup reasonably fast.