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-persist t
org-clock-report-include-clocking-task t) org-clock-report-include-clocking-task t)
#+END_SRC #+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 *** agenda
**** targets **** targets
The agenda files are limited to as few as possible to keep scanning and startup reasonably fast. The agenda files are limited to as few as possible to keep scanning and startup reasonably fast.