diff -r 48bcbca019e6 -r f58f3b88c49e emacs/lib/scrum.el --- a/emacs/lib/scrum.el Sun Sep 08 20:11:35 2024 -0400 +++ b/emacs/lib/scrum.el Sun Sep 08 21:14:30 2024 -0400 @@ -68,5 +68,102 @@ (defun org-dblock-write:burndown () "Generate a 'burndown' chart in the current buffer.") +;;; Projects +;; defining 'project' machinery here because we don't have a better +;; place to put it. These functions are intended to map projects +;; from 'skel' and 'project.el' into our task-based org system. + +;; Projects can contain many subprojects, which are identified by org +;; headings with a 'PROJECT' todo keyword. Projects and sub-projects +;; all have a 'VERSION' property assigned which can't be +;; inherited. The 'PROJECT' property itself can be inherited. + +;; project-info +(defcustom org-project-info-order '(details status tasks churn log files) + "Order in which sections of the 'project-info' dblock will appear." + :type 'list + :group 'scrum) + +(defun org-dblock-write:project-info (params) + "Generate a project-info section. + +The following keyword parameters can be passed to the info dynamic block: + +:location Set or override the project location which is inferred by + checking for a LOCATION property in the current tree, followed + by the value of the `project-current' function. + +:branch Set or override the project branch to display info for. Default + branch name is 'default'. + +:files When nil don't include the files table. +:churn When nil don't include the vc churn report. +:log when nil don't include the vc log. +:status when nil don't include vc status. +:details When nil don't include the project details section." + (let ((location (or (when-let ((param (plist-get params :location))) + (cl-coerce param 'string)) + (org-entry-get (point) "LOCATION") + (when-let ((kw (org-collect-keywords '("LOCATION")))) + (cadar kw)) + (project-root (project-current)))) + (point (point)) + (files (if-let ((val (plist-member params :files))) + (cadr val) + t)) + (churn (if-let ((val (plist-member params :churn))) + (cadr val) + t)) + (status (if-let ((val (plist-member params :log))) + (cadr val) + t)) + (log (if-let ((val (plist-member params :status))) + (cadr val) + t)) + (tasks (if-let ((val (plist-member params :tasks))) + (cadr val) + t)) + (details (if-let ((val (plist-member params :details))) + (cadr val) + t))) + (message "Generating info for project: %s" location) + (let* ((project (project-current nil location)) + (project-name (project-name project)) + (project-root (project-root project))) + (dolist (i org-project-info-order) + (pcase i + ('details (when details + (message "building project details...") + (insert "#+CALL: project-details() :dir " project-root "\n") + (org-babel-execute-maybe) + (org-table-align))) + ('status (when status + (message "building project status...") + (insert "#+CALL: hg-status() :dir " project-root "\n"))) + ('tasks (when tasks + (message "building project tasks...") + (insert "#+CALL: project-tasks() :dir " project-root "\n"))) + ('churn (when churn + (message "building project vc churn...") + (insert "#+CALL: hg-churn() :dir " project-root "\n"))) + ('log (when log + (message "building project vc log..."))) + ('files (when files + (message "building project file table...") + (insert "#+CALL: project-files() :dir " project-root "\n"))))) + (org-babel-execute-region point (point))))) + +(defun org-project-info () + "Insert or update a project-info dblock." + (interactive) + (if (re-search-forward (rx bol "#+BEGIN:" (+ space) "project-info") nil t) + (progn + (if (fboundp 'org-fold-show-entry) + (org-fold-show-entry) + (with-no-warnings (org-show-entry))) + (beginning-of-line)) + (org-create-dblock (list :name "project-info"))) + (org-update-dblock)) + (provide 'scrum) ;;; scrum.el ends here