0

1 Context

In a custom org-mode agenda view (in column mode), there is a column with label μ that shows "utility ranges" in brackets. Here is what it looks like (alongside the Category and TODO columns):

|Category |   TODO   | μ             |
|cat1     | COMPLETE | [0.1μ, 3 μ]   |
|cat2     | STARTED  | [0.2μ, 4 μ]   |
|cat2     | COMPLETE | [0.2 μ]       |
|cat2     | TODO     | [0.1μ, 3 μ]   |
|cat3     | COMPLETE | [0.2μ, 6 μ]   |

Here [0.2 μ] is just short-hand for [0.2 μ, 0.2 μ].

2 Problem

What I'd like is some conditional summation data which shows -- for each category -- the sum of the utility ranges for tasks which are in the DONE state (i.e., the sum of the lowest utilities and the highest utilities in enclosed in brackets). In this case it should show something like the following:

|Category |   TODO   | μ             |
|cat1     | COMPLETE | [0.1μ, 3 μ]   |
|cat2     | STARTED  | [0.2μ, 4 μ]   |
|cat2     | COMPLETE | [0.2 μ]       |
|cat2     | COMPLETE | [0.2 μ, 0.4μ] |
|cat2     | TODO     | [0.1μ, 3 μ]   |
|cat3     | STARTED  | [0.2μ, 6 μ]   |
cat1 μ: [0.1μ, 3 μ]
cat2 μ: [0.4 μ, 0.8 μ]
cat3 μ: [0.0 μ, 0.0 μ]

3 First Attempt

I have the following function which sums μ-ranges (or any other range enclosed in brackets):

(defun bracket-sum (begin end char)
  (interactive "r\nM String: ")
  (save-restriction
    (save-excursion
      (narrow-to-region begin end)
      (goto-char (point-min))
      (let ((suml 0)
            (sumr 0)
            (regexpl (concat "\\[ *\\([-0-9.]+\\) *" char " *,"))
            (regexpr (concat ", *\\([-0-9.]+\\) *" char "*\\]"))
            (regexpm (concat "\\[ *\\([-0-9.]+\\) *" char "*\\]"))
            )
        (while (re-search-forward regexpl nil t)
          (setq suml (+ suml (string-to-number (match-string 1)))))
        (goto-char (point-min))
        (while (re-search-forward regexpr nil t)
          (setq sumr (+ sumr (string-to-number (match-string 1)))))
        (goto-char (point-min))
        (while (re-search-forward regexpm nil t)
          (setq suml (+ suml (string-to-number (match-string 1))))
          (setq sumr (+ sumr (string-to-number (match-string 1)))))
        (message "[%s%s, %s%s]" suml char sumr char)
        ))))

It can be called by enclosing a text region with bracket expressions and calling i.e. (bracket-sum begin end "μ"). So for example the sum of

[0.1μ, 0.2 μ]
[0.1μ]
[0.1μ, 0.2 μ]

is [0.3μ, 0.5 μ].

From here I'm not sure how to work this into the agenda view information. Does anybody have any thoughts on how to do this?

1
+50

Here is a slightly revised version tested on GNU Emacs:

(defun bracket-sum-line-split-col3 (col3 unit-char)
  (let ((regex-pat1 (format "\\([-0-9.]+[ ]*\\)%s" unit-char))
        (regex-pat2 (format "\\([-0-9.]+[ ]*\\)%s[ ]*,[ ]*\\([-0-9.]+[ ]*\\)%s" unit-char unit-char)))
    (if (string-match regex-pat2 col3)
        (list (string-to-number (match-string 1 col3)) (string-to-number (match-string 2 col3)))
      (if (string-match regex-pat1 col3)
          (list (string-to-number (match-string 1 col3)) (string-to-number (match-string 1 col3)))
        )
      )
    )
  )

(defun bracket-sum-line (line unit-char)
  (if (string-match "|[ ]*\\(.+?\\)[ ]*|[ ]*\\(.+?\\)[ ]*|[ ]*\\(.+?\\)[ ]*|" line)
      (let ((col1 (match-string 1 line))
            (col2 (match-string 2 line))
            (col3 (match-string 3 line)))
        (let* ((ret (bracket-sum-line-split-col3 col3 unit-char))
               (val1 (car ret))
               (val2 (cadr ret)))
          (list col1 col2 val1 val2))
        )))

(defun bracket-sum-output (results unit-char)
  (let (retval)
    (maphash (lambda (key value)
               (push (format "|%s|%f %s|%f %s|" key (nth 0 value) unit-char (nth 1 value) unit-char) retval)
               (message "hash key: \"%s\"" key)
               )
             results)
    (push "|Category|col1|col2|" retval) ;; header
    (push "\nCOMPLETED SUMS" retval)
    (insert (mapconcat 'identity retval "\n")) ;;retval
    ) ;; end let
)

(defun bracket-sum (begin end char)
  (interactive "r\nM String: ")
  (save-restriction
    (save-excursion
      (narrow-to-region begin end)
      (goto-char (point-min))
      (let ((result (make-hash-table :test 'equal))
            (curr-line 1)
            (begin (point))
            (end (point-max)))
        (while (< (point) end)
          ;; (buffer-substring
          (forward-line 1)

          ;; work done here
          (message "where %d %d %d \"%s\"" begin (point) curr-line (buffer-substring begin (- (point) 1)))
          (if (> curr-line 1) ; skip table header
              (let* ((ret (bracket-sum-line (buffer-substring begin (- (point) 1))  char))
                     (col1 (nth 0 ret))
                     (col2 (nth 1 ret))
                     (val1 (nth 2 ret))
                     (val2 (nth 3 ret)))
                (if (string= col2 "COMPLETE")
                    (if (gethash col1 result)
                        (let* ((res (gethash col1 result))
                               (res1 (nth 0 res))
                               (res2 (nth 1 res)))
                          (puthash col1 (list (+ val1 res1) (+ val2 res2)) result)) ;; existing entry
                      (puthash col1 (list val1 val2) result)) ;; new entry
                  (unless (gethash col1 result)
                    (puthash col1 (list 0 0) result))) ;; not complete
                )
            ) ;; end if not table header if

          ;; goto next line
          (setq curr-line (+ 1 curr-line))
          (setq begin (point))) ;; end while

        (message "%s" result)
        (bracket-sum-output result char) ;; print output
        ))))

ok so what is happening here. To Run:

1) mark (aka select) the area in the org buffer leaving the cursor on the line below the last one in the table

step 1

2) call the function

step 2

3) provide the column arg

step 3

Here is what I get:

results

then just go into the results and hit tab and org mode will format it. I only tested it in GNU Emacs.

James

  • I'm looking forward to trying this out. Have you gotten it work on an org agenda buffer? Running (format "%s" (bracket-sum "*Org Agenda*" "μ")) yields "(Category: nil, 0.000000 μ, 0.000000 μ.)" incorrectly on my machine. – George Aug 10 '17 at 1:48
  • What is C-u C-x C-e bound to on your emacs? I run spacemacs so the keybindings are somewhat different than stock emacs machine so I have to call this manually. – George Aug 10 '17 at 1:49
  • oh, sorry, I was not clear. To speed up testing I created a separate file called "conditional_sum.org" and called the function at the end of the file. I put (format "%s" (bracket-sum "conditional_sum.org" "μ")) on the last line of the .el file. In GNU emacs the command sequence "C-u" followed by "C-X C-e" means evaluate the function and paste the results into the current buffer. I have never used spacemacs so I am unaware of the differences. – James Anderson Aug 10 '17 at 1:55
  • Is there a way to port this so that it works in the agenda buffer column view? – George Aug 10 '17 at 1:57
  • 1
    yeah, for sure. I would have to get familiar with spacemacs. I don't know if I can get to it today. – James Anderson Aug 10 '17 at 2:00

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.