ENH update iterator scanner

This commit is contained in:
Nathan Dwarshuis 2022-04-02 19:03:07 -04:00
parent 564b231e1c
commit 56436f7147
1 changed files with 176 additions and 182 deletions

View File

@ -249,17 +249,6 @@ that file as it currently sits on disk.")
;; functions to construct nodes within state
(defun org-x-dag-build-meta (file point level todo title tags planning props parent)
(list :file file
:point point
:level level
:todo todo
:title title
:tags tags
:planning planning
:props props
:buffer-parent parent))
;; state lookup functions
;;
;; all functions with `org-x-dag->' or `org-x-dag-id->' depend on the value of
@ -315,7 +304,7 @@ that file as it currently sits on disk.")
(plist-get :buffer-status)))
(defun org-x-dag-id->buffer-parent (id)
(-> (org-x-dag-id->node-meta id)
(-> (org-x-dag-id->hl-meta id)
(plist-get :buffer-parent)))
(defun org-x-dag-id->ns (id)
@ -375,7 +364,7 @@ highest in the tree."
(cl-labels
((ascend
(id tags)
(-if-let (parent (org-x-dag-id->hl-meta-prop id :buffer-parent))
(-if-let (parent (org-x-dag-id->buffer-parent id))
;; tags in the front of the list have precedence over latter tags,
;; so putting parent tags at the end means child tags have
;; precedence
@ -1300,19 +1289,27 @@ used for optimization."
(when (and (< (point) prop-beg) (looking-at org-planning-line-re))
(org-element-planning-parser prop-beg))))
(defun org-x-dag-nreverse-tree (tree)
(--each tree
(setcdr it (org-x-dag-nreverse-tree (cdr it))))
(nreverse tree))
(defun org-x-dag-get-buffer-nodes (file-meta kws target-props)
(goto-char (point-min))
(let* ((line-re (org-x-dag-line-regexp kws))
(first-hl (org-x-dag-next-headline))
;; If not on a headline, check for a property drawer with links in it
(this-file-links (unless (= ?* (following-char))
(org-x-dag-get-parent-links nil first-hl)))
(pps (--map (cons it (org-re-property it nil t)) target-props))
(id-prop (org-re-property "ID" nil t))
(first-hl (unless (= ?* (following-char))
(org-x-dag-next-headline)))
;; If not on a headline, check for a property drawer with links in it
(this-file-links (when first-hl
(org-x-dag-get-parent-links nil first-hl)))
;; stack vars
bare-stack node-level bury-level
bare-stack node-stack bury-level
;; data vars
this-id this-level this-todo this-tags this-links this-pblock pbeg pend
this-id this-level this-todo this-tags this-links this-pblock
this-parent this-buffer-parent
pbeg pend
;; return
acc acc-links)
(when first-hl
@ -1333,9 +1330,9 @@ used for optimization."
(unless (and bury-level (< bury-level this-level))
;; Adjust the stack so that the top headline is the parent of the
;; current headline
(when (and node-level (<= this-level node-level))
(setq node-level nil))
(unless node-level
(while (and node-stack (<= this-level (nth 0 (car node-stack))))
(!cdr node-stack))
(unless node-stack
(while (and bare-stack (<= this-level (nth 0 (car bare-stack))))
(!cdr bare-stack)))
;; Add the current headline to accumulator if it is a node, but only if
@ -1347,41 +1344,50 @@ used for optimization."
pend (nth 2 this-pblock)
this-id (org-x-dag-get-local-property pbeg pend id-prop)))
(setq bury-level nil
this-buffer-parent (nth 2 (car node-stack))
this-links (or (org-x-dag-get-parent-links (nth 3 this-pblock)
next-pos)
(unless node-level
(unless node-stack
(nth 2 (car bare-stack)))))
(when this-tags
(setq this-tags (split-string this-tags ":")))
(when (and (not node-level) bare-stack)
(when (and (not node-stack) bare-stack)
(setq this-tags (->> (car bare-stack)
(nth 1)
(append this-tags))))
(-> (list
:id this-id
:parents this-links
:node-meta
`(,@file-meta
:point ,this-point
:effort ,(when this-title
(get-text-property 0 'effort this-title))
:level ,this-level
:todo ,this-todo
:title ,(if this-title (substring-no-properties this-title) "")
:tags ,this-tags
:planning ,(org-x-dag-parse-this-planning (nth 0 this-pblock))
:props ,(org-x-dag-get-local-properties pbeg pend pps)))
(!cons acc))
(->> (list :point this-point
:buffer-parent this-buffer-parent
:effort (when this-title
(get-text-property 0 'effort this-title))
:level this-level
:todo this-todo
:title (if this-title (substring-no-properties this-title) "")
:tags this-tags
:planning (org-x-dag-parse-this-planning (nth 0 this-pblock))
:props (org-x-dag-get-local-properties pbeg pend pps))
(append file-meta)
(list :id this-id
:parents (if this-buffer-parent
`(,this-buffer-parent ,@this-links)
this-links)
:node-meta)
(list)
(setq this-node))
(if node-stack
(-> (setq this-parent (nth 1 (car node-stack)))
(setcdr (cons this-node (cdr this-parent))))
(!cons this-node acc))
(!cons (list this-level this-node this-id) node-stack)
(when this-links
(!cons (cons this-id this-links) acc-links))
(setq node-level this-level))
(!cons (cons this-id this-links) acc-links)))
;; Underneath a node but not on a node, therefore we are buried
(node-level
(node-stack
(setq bury-level this-level))
;; Anything else means we are on a bare headline above any nodes
(t
(setq bury-level nil
node-level nil)
;; node-level nil)
node-stack nil)
(when this-tags
(setq this-tags (split-string this-tags ":")))
(-> (list this-level
@ -1391,7 +1397,7 @@ used for optimization."
this-file-links))
(!cons bare-stack)))))
(goto-char next-pos))
(list (nreverse acc) acc-links)))
(list (org-x-dag-nreverse-tree acc) acc-links)))
(defun org-x-dag-buffer-nodes-to-tree (nodes)
(cl-labels
@ -1449,27 +1455,27 @@ used for optimization."
(declare (indent 2))
(let ((err (org-x-dag-bs :error "Child error")))
`(-if-let ((x . xs) ,bss)
;; (if (org-x-dag-bs-error-p x) (progn (print x) ',err)
(if (org-x-dag-bs-error-p x) ',err
(let ((acc x) r)
(while xs
(let ((acc (cadr x)) r final)
(while (and (not final) xs)
(setq x (car xs))
(if (org-x-dag-bs-error-p x)
(setq acc ',err
xs nil)
(setq it x
(setq final ',err)
(setq it (cadr x)
r ,rank-form)
(unless r
(error "You forgot the difference between Maybe and Either"))
(if (org-x-dag-bs-error-p r)
(setq acc r
xs nil)
(when r
(setq acc x))
(setq final r)
(when (cadr r)
(setq acc (cadr x)))
(if ,stop-form
(setq acc (org-x-dag-bs :valid acc)
xs nil)
(setq final (org-x-dag-bs :valid acc))
(!cdr xs)))))
(org-x-dag-bs>>= acc ,trans-form)))
(when (not final)
(setq final (org-x-dag-bs :valid acc)))
(org-x-dag-bs>>= final ,trans-form)))
(org-x-dag-bs :valid ,default))))
(defun org-x-dag-bs-error-kw (type-name kw)
@ -1529,7 +1535,8 @@ used for optimization."
(`((:sp-task :task-complete ,_) ,_) t)
(`(,_ (:sp-proj :proj-complete ,_)) nil)
(`(,_ (:sp-iter :iter-complete ,_)) nil)
(`(,_ (:sp-task :task-complete ,_)) nil))
(`(,_ (:sp-task :task-complete ,_)) nil)
(e (error "Unmatched pattern: %S" e)))
(org-x-dag-bs :valid))
(pcase acc
(`(:sp-proj :proj-complete ,_) nil)
@ -1617,43 +1624,54 @@ used for optimization."
;; TODO these next two could be made more efficient by cutting out the
;; earlystop form and returning error in the rank form (the trans form is
;; still needed in case there is only one child)
(defun org-x-dag-bs-action-subiter-complete-fold (child-bss type-name comp-key)
(declare (indent 1))
(org-x-dag-bs-fold-children child-bss `(,comp-key ,it-comptime)
(->> (pcase `(,si-a ,si-b)
(defun org-x-dag-bs-action-subiter-complete-fold (child-bss comptime type-name comp-key)
(declare (indent 2))
(org-x-dag-bs-fold-children child-bss `(,comp-key ,comptime)
(->> (pcase `(,acc ,it)
(`((:si-complete ,_) (:si-complete ,_)) nil)
(`((:si-complete ,_) ,_) t)
(`(,_ (:si-complete ,_)) nil))
(`(,_ (:si-complete ,_)) nil)
(e (error "Unmatched pattern: %S" e)))
(org-x-dag-bs :valid))
(pcase acc
(`(:si-complete ,_) nil)
(_ t))
(pcase it
(`(:si-complete ,_)
(org-x-dag-bs :valid `(,comp-key ,it-comptime)))
(org-x-dag-bs :valid `(,comp-key ,comptime)))
(_
(->> (format "Completed %s cannot have active children" type-name)
(org-x-dag-bs :error))))))
(defun org-x-dag-bs-action-subiter-todo-fold (child-bss type-name active-key default)
(org-x-dag-bs-fold-children child-bss default
(pcase `(,si-a ,si-b)
(`((:si-active (,ts-a ,dead-a)) (:si-active (,ts-b ,dead-b)))
(let ((dt-a (org-ml-timestamp-get-start-time ts-a))
(dt-b (org-ml-timestamp-get-start-time ts-b)))
(pcase `(,acc ,it)
(`((:si-active ,a) (:si-active ,b))
(-let (((&plist :sched as :dead ad) a)
((&plist :sched bs :dead bd) b))
(cond
((not (eq dead-a dead-b))
(->> "All sub-iter timestamps must be scheduled or deadlined"
((or (xor as bs) (xor ad bd))
(->> "All sub-iters must have the same planning configuration"
(org-x-dag-bs :error)))
((xor (org-ml-time-is-long dt-a) (org-ml-time-is-long dt-b))
(->> "All sub-iter timestamps must be long or short"
((and as bs (xor (org-ml-time-is-long as) (org-ml-time-is-long bs)))
(->> "Sub-iters must have scheduled timestamp with same length"
(org-x-dag-bs :error)))
((and ad bd (xor (org-ml-time-is-long ad) (org-ml-time-is-long bd)))
(->> "Sub-iters must have deadline timestamp with same length"
(org-x-dag-bs :error)))
;; ASSUME this won't fail since the datetimes are assumed to be the
;; same length as per rules above
((and ad bd)
(->> (org-x-dag-datetime< (org-ml-timestamp-get-start-time ad)
(org-ml-timestamp-get-start-time bd))
(org-x-dag-bs :valid)))
(t
;; ASSUME this won't fail since the datetimes are assumed to be the
;; same length as per rules above
(org-x-dag-bs :valid (org-x-dag-datetime< dt-a dt-b))))))
(->> (org-x-dag-datetime< (org-ml-timestamp-get-start-time as)
(org-ml-timestamp-get-start-time bs))
(org-x-dag-bs :valid))))))
(`((:si-active ,_) ,_) (org-x-dag-bs :valid nil))
(`(,_ (:si-active ,_)) (org-x-dag-bs :valid t)))
(`(,_ (:si-active ,_)) (org-x-dag-bs :valid t))
(`(,_ ,_) (org-x-dag-bs :valid nil)))
(pcase acc
(`(:si-active ,_) t)
(_ nil))
@ -1665,12 +1683,12 @@ used for optimization."
(org-x-dag-bs :valid `(,active-key ,ts-data))))))
(defun org-x-dag-node-is-iterator-p (node)
(org-x-dag-node-data-is-iterator-p (plist-get node :node-data)))
(org-x-dag-node-data-is-iterator-p (plist-get node :node-meta)))
(defun org-x-dag-bs-action-subiter-inner (node-data child-bss)
(org-x-dag-bs-action-with-closed node "sub-iterators"
(org-x-dag-bs-action-with-closed node-data "sub-iterators"
`(:si-complete ,it-comptime)
(org-x-dag-bs-action-subiter-complete-fold child-bss
(org-x-dag-bs-action-subiter-complete-fold child-bss it-comptime
"sub-iterators" :si-complete)
(-let (((sched dead) (-some->> it-planning
(org-ml-get-properties '(:scheduled :deadline)))))
@ -1679,21 +1697,21 @@ used for optimization."
(org-x-dag-bs :error "Sub-iterators with children cannot be scheduled"))
((and dead child-bss)
(org-x-dag-bs :error "Sub-iterators with children cannot be deadlined"))
((and (not child-bss) (not (xor sched dead)))
(org-x-dag-bs :error "Sub-iterators must either be deadlined or scheduled"))
;; ((and (not child-bss) (not (xor sched dead)))
;; (org-x-dag-bs :error "Sub-iterators must either be deadlined or scheduled"))
((org-x-dag-node-data-is-iterator-p node-data)
(org-x-dag-bs :error "Iterators cannot be nested"))
((equal it-todo org-x-kw-todo)
(org-x-dag-bs-action-subiter-todo-fold child-bss
"sub-iterator" :si-active
`(:si-active ,(or sched dead) ,(and dead t))))
`(:si-active (:sched ,sched :dead ,dead))))
(t
(org-x-dag-bs-error-kw "Sub-iterator" it-todo))))))
(defun org-x-dag-bs-action-iter-inner (node-data child-bss)
(org-x-dag-bs-action-with-closed node-data "iterators"
`(:iter-complete ,it-comptime)
(org-x-dag-bs-action-subiter-complete-fold child-bss
(org-x-dag-bs-action-subiter-complete-fold child-bss it-comptime
"iterators" :iter-complete)
(cond
((and child-bss (-some->> it-planning (org-ml-get-property :scheduled)))
@ -1756,28 +1774,26 @@ used for optimization."
(t
(org-x-dag-bs-error-kw "Endpoint goal" it-todo)))))
(defun org-x-dag-bs-with-treetop-error (tree parent-id)
(defun org-x-dag-bs-with-treetop-error (tree)
(declare (indent 3))
(-let* (((node . children) tree)
((&plist :id i :parents links :node-meta m) node)
(ps (cons parent-id links))
((&plist :id i :parents ps :node-meta m) node)
(this (->> (org-x-dag-bs :error "Children not allowed")
(org-x-dag-node i ps parent-id m))))
(cons this (--mapcat (org-x-dag-bs-with-treetop-error it i) children))))
(org-x-dag-node i ps m))))
(cons this (--mapcat (org-x-dag-bs-with-treetop-error it) children))))
(defun org-x-dag-bs-with-treetop (tree node-fun)
(declare (indent 3))
(-let* ((((&plist :id i :parents links :node-meta m) . children) tree)
(-let* ((((&plist :id i :parents ps :node-meta m) . children) tree)
(bs (if children (org-x-dag-bs :error "Children not allowed")
(funcall node-fun m)))
(top (org-x-dag-node i links nil m bs)))
(cons top (--mapcat (org-x-dag-bs-with-treetop-error it i) children))))
(top (org-x-dag-node i ps m bs)))
(cons top (--mapcat (org-x-dag-bs-with-treetop-error it) children))))
(defun org-x-dag-node (id parents buffer-parent node-meta bs)
(defun org-x-dag-node (id parents node-meta bs)
(list :id id
:parents parents
:node-meta (list :hl-meta node-meta
:buffer-parent buffer-parent
:buffer-status bs)))
(defmacro org-x-dag-node-fmap (node form)
@ -1786,34 +1802,32 @@ used for optimization."
`(-let (((&plist :id i
:parents ps
:node-meta (&plist :hl-meta h
:buffer-parent p
:buffer-status it))
,node))
(org-x-dag-node i ps p h ,form)))
(org-x-dag-node i ps h ,form)))
(defun org-x-dag-bs-with-children (tree parent child-fun node-fun concat-fun)
(defun org-x-dag-bs-with-children (tree child-fun node-fun concat-fun)
(declare (indent 3))
;; TODO this is super inefficient, make a plist mapper function
(-let* (((node . children) tree)
((&plist :id i :parents links :node-meta m) node)
((shallow rest) (->> (--map (funcall child-fun it i) children)
(apply #'-zip-lists)))
(ps (if parent (cons parent links) links)))
((&plist :id i :parents ps :node-meta m) node)
((shallow rest) (->> (--map (funcall child-fun it) children)
(apply #'-zip-lists))))
(list (->> shallow
(--map (plist-get (plist-get it :node-meta) :buffer-status))
(funcall node-fun m)
(org-x-dag-node i ps parent m))
(org-x-dag-node i ps m))
(funcall concat-fun shallow rest))))
;; Tree a -> (Tree a -> (b, [d])) -> (a -> [b] -> c) -> (c, [d])
(defun org-x-dag-bs-with-children-1 (tree parent child-fun node-fun)
(org-x-dag-bs-with-children tree parent child-fun node-fun
(defun org-x-dag-bs-with-children-1 (tree child-fun node-fun)
(org-x-dag-bs-with-children tree child-fun node-fun
(lambda (shallow deep)
(append shallow (-flatten-n 1 deep)))))
;; Tree a -> (Tree a -> (b, ([d], [e]))) -> (a -> [b] -> c) -> (c, ([d], [e]))
(defun org-x-dag-bs-with-children-2 (tree parent child-fun node-fun)
(org-x-dag-bs-with-children tree parent child-fun node-fun
(defun org-x-dag-bs-with-children-2 (tree child-fun node-fun)
(org-x-dag-bs-with-children tree child-fun node-fun
(lambda (shallow deep)
(--reduce-from (-let (((a b) acc)
((as bs) it))
@ -1821,43 +1835,43 @@ used for optimization."
`(,shallow nil)
deep))))
(defun org-x-dag-bs-action-subiter (tree parent)
(defun org-x-dag-bs-action-subiter (tree)
(org-x-dag-bs-with-children-1
tree
parent
#'org-x-dag-bs-action-subiter
#'org-x-dag-bs-action-subiter-inner))
(defun org-x-dag-bs-action-iter (tree parent)
(defun org-x-dag-bs-action-iter (tree)
(org-x-dag-bs-with-children-1
tree
parent
#'org-x-dag-bs-action-subiter
(lambda (node child-bss)
(org-x-dag-node-fmap node
(org-x-dag-bs-fmap (org-x-dag-bs-action-iter-inner it child-bss)
`(:sp-proj it))))))
(lambda (node-data child-bss)
(org-x-dag-bs-fmap (org-x-dag-bs-action-iter-inner node-data child-bss)
(cons :sp-proj it)))))
(defun org-x-dag-bs-action-project (tree parent)
(defun org-x-dag-bs-action-project (tree)
(if (org-x-dag-node-is-iterator-p (car tree))
(-let (((iter subiters) (org-x-dag-bs-action-iter tree nil)))
(-let (((iter subiters) (org-x-dag-bs-action-iter tree)))
`(,iter (nil ,subiters)))
(org-x-dag-bs-with-children-2
tree
parent
#'org-x-dag-bs-action-project
#'org-x-dag-bs-action-project-inner)))
;; TODO need to check for created timestamps
(defun org-x-dag-bs-action (node-tree)
;; TODO these types might not line up properly
(-let (((p (ps is)) (org-x-dag-bs-action-project node-tree nil)))
`(,p ,@ps ,@is)))
(cl-flet
((lift-subiter
(node)
(org-x-dag-node-fmap node
(org-x-dag-bs-fmap it
(cons :sp-subiter it)))))
(-let (((p (ps is)) (org-x-dag-bs-action-project node-tree)))
`(,p ,@ps ,@(-map #'lift-subiter is)))))
(defun org-x-dag-bs-epg-outer (tree parent)
(defun org-x-dag-bs-epg-outer (tree)
(org-x-dag-bs-with-children-1
tree
parent
#'org-x-dag-bs-epg-outer
#'org-x-dag-bs-epg-inner))
@ -1865,7 +1879,7 @@ used for optimization."
(--map (org-x-dag-node-fmap it (org-x-dag-bs-fmap it `(,key ,it))) nodes))
(defun org-x-dag-bs-epg (tree)
(-let (((n ns) (org-x-dag-bs-epg-outer tree nil)))
(-let (((n ns) (org-x-dag-bs-epg-outer tree)))
(org-x-dag-bs-prefix :endpoint `(,n ,@ns))))
(defun org-x-dag-bs-toplevel-goal-inner (type-name node-data child-bss)
@ -1881,17 +1895,16 @@ used for optimization."
(t
(org-x-dag-bs-error-kw type-name todo)))))
(defun org-x-dag-bs-toplevel-goal-outer (type-name tree parent)
(defun org-x-dag-bs-toplevel-goal-outer (type-name tree)
(org-x-dag-bs-with-children-1
tree
parent
(lambda (tree parent)
(org-x-dag-bs-toplevel-goal-outer type-name tree parent))
(lambda (tree)
(org-x-dag-bs-toplevel-goal-outer type-name tree))
(lambda (node-data child-bss)
(org-x-dag-bs-toplevel-goal-inner type-name node-data child-bss))))
(defun org-x-dag-bs-toplevel-goal (type-name type-key tree)
(-let (((n ns) (org-x-dag-bs-toplevel-goal-outer type-name tree nil)))
(-let (((n ns) (org-x-dag-bs-toplevel-goal-outer type-name tree)))
(org-x-dag-bs-prefix type-key `(,n ,@ns))))
(defun org-x-dag-bs-ltg (tree)
@ -1994,9 +2007,7 @@ used for optimization."
((nodes links)
(org-x-with-file file
(org-x-dag-get-buffer-nodes meta org-todo-keywords-1 props))))
(list (->> (org-x-dag-buffer-nodes-to-tree nodes)
(-mapcat bs-fun))
links)))
`(,(-mapcat bs-fun nodes) ,links)))
;; network status
@ -2037,13 +2048,6 @@ used for optimization."
(format "%s: %s" msg)
(org-x-dag-bs :error)))
(defun org-x-dag-id-is-buffer-leaf (adjlist id)
(->> (plist-get (ht-get adjlist id) :children)
(--none-p (-> (ht-get adjlist it)
(plist-get :node-meta)
(plist-get :buffer-parent)
(equal id)))))
(defun org-x-dag-ns-toplevel (tbl adjlist links ns)
(let ((h (alist-get tbl ns)))
(org-x-dag-each-links links
@ -2077,7 +2081,7 @@ used for optimization."
(cond
((org-x-dag-bs-error-p (ht-get h id))
:error)
((and checkleafp (not (org-x-dag-id-is-buffer-leaf adjlist id)))
((and checkleafp (not (org-x-dag-get-children adjlist id)))
:non-leaf)
(t :valid)))
(reduce-valid
@ -2204,6 +2208,7 @@ used for optimization."
(->> (plist-get (ht-get adjlist id) :children)
(--filter (-> (ht-get adjlist it)
(plist-get :node-meta)
(plist-get :hl-meta)
(plist-get :buffer-parent)
(equal id)))))
@ -2239,16 +2244,9 @@ used for optimization."
(defun org-x-dag-ht-propagate-up (adjlist h-key s-key ns)
(cl-labels
((get-children
(adjlist id)
(->> (plist-get (ht-get adjlist id) :children)
(--filter (-> (ht-get adjlist it)
(plist-get :node-meta)
(plist-get :buffer-parent)
(equal id)))))
(propagate
((propagate
(htbl id)
(-let* ((cs (get-children adjlist id))
(-let* ((cs (org-x-dag-get-children adjlist id))
(rs (--map (propagate htbl it) cs))
;; TODO there isn't a better way to do this? (seems like I'm
;; accessing either/maybe types too many times)
@ -3194,20 +3192,22 @@ except it ignores inactive timestamps."
(-mapcat #'split-parent-goals))))
(defun org-x-dag-scan-iterators ()
(cl-flet*
((format-result
(tags cat key)
(-let ((status (org-x-dag-headline-get-iterator-status key)))
(-> (org-x-dag-format-tag-node cat tags key)
(org-add-props nil
'x-status status)))))
;; TODO this will only scan toplevel iterators
(org-x-dag-with-files (org-x-dag->action-files)
(org-x-dag-id->is-toplevel-p it)
(let ((tags (org-x-dag-id->tags nil it)))
(when (eq (cadr (org-x-dag-id->goal-status 'current id)) :planned)
(when (org-x-dag-id->is-iterator-p it)
(list (format-result tags it-category it))))))))
(cl-flet
((format-id
(id status-data)
(let ((status (car status-data)))
(when (memq status '(:iter-empty :iter-active))
(let ((tags (org-x-dag-id->tags nil id)))
(-> (org-x-dag-format-tag-node tags id)
(org-add-props nil
'x-status status)))))))
(with-temp-buffer
(org-mode)
(->> (org-x-dag->action-files)
(org-x-dag-files->ids)
(--map (pcase (org-x-dag-id->bs it)
(`(:valid (:sp-proj . ,s)) (format-id it s))))
(-non-nil)))))
(defun org-x-dag-get-task-nodes (pred id)
(declare (indent 2))
@ -3375,30 +3375,24 @@ except it ignores inactive timestamps."
(defun org-x-dag-scan-archived ()
(cl-flet
((format-key
(category key)
(let ((tags (org-x-dag-id->tags nil key)))
;; TODO is this what I actually want?
(when (memq (cadr (org-x-dag-id->goal-status 'current key)) '(:planned :committed))
(-let (((is-archivable is-project)
(-if-let (children (org-x-dag-id->buffer-children key))
(-> (org-x-dag-headline-get-project-status key tags children)
(alist-get org-x-project-status-priorities)
(eq :archivable)
(list t))
(-> (org-x-dag-id->task-status id)
(alist-get org-x-headline-task-status-priorities)
(eq :archivable)
(list t)))))
(when is-archivable
(-> (org-x-dag-format-tag-node category tags key)
(id bs)
(-when-let ((comptime is-project)
(pcase bs
(`(:sp-proj :proj-complete ,c) `(,c t))
(`(:sp-task :task-complete ,c) `(,c nil))))
(-let ((epoch (plist-get comptime :epoch)))
(when (org-x-dag-time-is-archivable-p epoch)
(let ((tags (org-x-dag-id->tags nil id)))
(-> (org-x-dag-format-tag-node tags id)
(org-add-props nil
'x-project-p is-project))))))))
(org-x-dag-with-files (org-x-get-action-files)
(org-x-dag-id->is-toplevel-p it)
(if (org-x-dag->is-iterator-p it)
(->> (org-x-dag-id->buffer-children it)
(--map (format-key it-category it)))
(list (format-key it-category it))))))
(with-temp-buffer
(org-mode)
(->> (org-x-dag->action-files)
(org-x-dag-files->ids)
(--map (pcase (org-x-dag-id->bs it)
(`(:valid ,v) (format-key it v))))
(-non-nil)))))
(defun org-x-dag--classify-goal-link (which which-goal id)
(let ((f (org-x-dag-id->file id)))