Bastien <b...@gnu.org> writes: > Hi John, > > John J Foerch <jjfoe...@earthlink.net> writes: > >> These thoughts lead me to suggest that maybe org-log-note-headings is no >> longer sufficient to its original purpose, because extensions wish to >> parse state changes, but that blocks users from configuring the formats. >> Perhaps it is time to replace it with something that guarantees ability >> to parse. > > I see the problem -- what do you suggest as a useful replacement for > `org-log-note-headings'? > >> Thoughts? > > I understand your point but I need more arguments to spend time on > improving this. "Argument" = code that we would like to run and that > would need a rewrite of `org-log-note-headings'. > > Thanks!
I have been experimenting with parsing the format-string to build a regexp to match the generated-strings. This approach depends upon the parsability of the expansions of each of the percent-codes. As concerns org-log-note-headings, %t, %T, %d, %D, %s, %S, and %u all have parseable expansions, as far as I can tell. I'm not sure about %U, but if the rest of the string is not too complicated, it shouldn't be a problem. Format-code flag, width, and precision add some complexity to the problem of generating regexps to match the codes, and I haven't done that bit yet. Overall I think this could be a very viable approach, and I'll paste my scraps of code below: ;;; parsing state changes ;;; (defun org-split-format-string (str) (let ((case-fold-search t) (format-regexp "%[+ #-0]*[0-9]*\\(\\.[0-9]+\\)?[%a-z]") (parts (list)) (s 0)) (while (string-match format-regexp str s) (let* ((beg (match-beginning 0)) (end (match-end 0)) (before (substring str s beg))) (unless (string= before "") (push before parts)) (push (substring str beg end) parts) (setq s end))) (let ((last (substring str s))) (unless (string= last "") (push last parts))) (nreverse parts))) ;;tests (equal (org-split-format-string "CLOSING NOTE %t") '("CLOSING NOTE " "%t")) (equal (org-split-format-string "State %-12s from %-12S %t") '("State " "%-12s" " from " "%-12S" " " "%t")) (equal (org-split-format-string "foo %t bar") '("foo " "%t" " bar")) (equal (org-split-format-string "foo") '("foo")) (equal (org-split-format-string "%s") '("%s")) (equal (org-split-format-string "%s%t") '("%s" "%t")) (defun org-get-format-parser (f) (let ((format-regexp "^%\\([+ #-0]*\\)\\([0-9]*\\)\\(\\.[0-9]+\\)?\\([%a-z]\\)$")) (string-match format-regexp f) (let ((flag (match-string 1 f)) (numb (match-string 2 f)) (prec (match-string 3 f)) (code (match-string 4 f))) (cond ;; hardcode format codes for now.. later, pass them in as an ;; alist or something. ((string= "t" code) "\\(\\[.*?\\]\\)") ;; inactive timestamp ((string= "T" code) "\\(<.*?>\\)") ;; active timestamp ((string= "d" code) "\\(\\[.*?\\]\\)") ;; inactive short-format timestamp ((string= "D" code) "\\(<.*?>\\)") ;; active short-format timestamp ((string= "s" code) "\\(\".*?\"\\)") ;; new TODO state ((string= "S" code) "\\(\".*?\"\\)") ;; old TODO state ((string= "u" code) "\\(\\w+\\)") ;; user name ((string= "U" code) "\\(.*\\)") ;; full user name (t (error "Unsupported format: %s" f)))))) (defun org-parse-formatted-text (fmt str) (let* ((sfmt (org-split-format-string fmt)) (regexp (concat "^" (apply 'concat (mapcar (lambda (x) (if (equal ?% (aref x 0)) (org-get-format-parser x) (regexp-quote x))) sfmt)) "$"))) regexp)) ;; (org-parse-formatted-text "State %-12s from %-12S %t" "") ;; => "^State \\(\".*?\"\\) from \\(\".*?\"\\) \\(\\[.*?\\]\\)$" ;;; ;;; end parsing state changes Thank you -- John Foerch