diff --git a/README.org b/README.org index 605b7bc..2a52476 100644 --- a/README.org +++ b/README.org @@ -68,6 +68,7 @@ Installing with [[https://framagit.org/steckerhalter/quelpa][Quelpa]] is easy: - [[#ancestordescendant-predicates][Ancestor/descendant predicates]] - [[#datetime-predicates][Date/time predicates]] - [[#functions--macros][Functions / Macros]] +- [[#dynamic-block][Dynamic block]] - [[#tips][Tips]] :END: @@ -396,6 +397,36 @@ Examples: Expands into a call to ~org-ql-select~ with the same arguments. For convenience, arguments should be unquoted. +** Dynamic block + +Org QL provides a dynamic block that lists entries in the current document matching a query. In the header, these parameters are supported: + ++ ~:query~: An Org QL query expression in either sexp or non-sexp form. ++ ~:columns~ A list of columns, including ~heading~, ~todo~, ~priority~, ~deadline~, ~scheduled~. ++ ~:sort~ One or a list of Org QL sorting methods (see ~org-ql-select~). ++ ~:take~ Optionally take a number of results from the front (a positive number) or the end (a negative number) of the results. ++ ~:ts-format~ Optional format string used to format timestamp-based columns. + +The heading column is formatted as a link to the heading (not shown in the following example). + +For example, this dynamic block shows the first seven headings that are to-do items with priority A or B, sorted by deadline then priority, with certain columns and timestamp format: + +# NOTE: These results are edited manually because the Org links don't display well in the Info manual. + +#+BEGIN_SRC org + ,#+BEGIN: org-ql :query "todo: priority:A,B" :columns (todo priority deadline heading) :sort (deadline priority) :take 7 :ts-format "%Y-%m-%d %H:%M" + | Todo | Priority | Deadline | Heading | + |------+----------+------------------+---------------------------------------| + | TODO | A | 2017-07-07 00:00 | Take over the world | + | TODO | B | 2017-07-10 00:00 | Renew membership in supervillain club | + | TODO | A | 2017-07-15 00:00 | Take over the universe | + | TODO | B | 2017-07-21 00:00 | Internet | + | TODO | A | 2017-08-01 00:00 | Spaceship lease | + | TODO | A | | Skype with president of Antarctica | + | TODO | B | | Take over Mars | + ,#+END: +#+END_SRC + ** Tips + Org QL View buffers can be bookmarked with Emacs bookmark commands, e.g. =C-x r m=. This also integrates with [[https://github.com/alphapapa/org-sidebar][org-sidebar]] and [[https://github.com/alphapapa/burly.el][Burly]]. @@ -413,6 +444,7 @@ Expands into a call to ~org-ql-select~ with the same arguments. For convenience + View dispatcher using =transient.el= (like Magit), bound to =v= in search/view buffers. + Predicate =link=, which matches descriptions and targets in Org links. + Emacs bookmark support: Org QL View buffers can be bookmarked with, e.g. =C-x r m= and shown with, e.g. =C-x r b=. (This also enables view restoration with [[https://github.com/alphapapa/burly.el][Burly]].) ++ Dynamic block support. + Mascot. *Changed* diff --git a/notes.org b/notes.org index 8082013..a66e80c 100644 --- a/notes.org +++ b/notes.org @@ -16,7 +16,7 @@ * [#A] Overview -#+BEGIN: org-ql :query (todo "UNDERWAY") :format (priority todo heading) :sort (priority date) :ts-format "%Y-%m-%d %H:%M" +#+BEGIN: org-ql :query (todo "UNDERWAY") :columns (priority todo heading) :sort (priority date) :ts-format "%Y-%m-%d %H:%M" | Priority | Todo | Heading | |----------+----------+--------------------------------------------------------------------| | A | UNDERWAY | [[Dynamic blocks][Dynamic blocks]] | @@ -206,7 +206,7 @@ For example, [[https://egli.dev/posts/using-org-mode-for-meeting-minutes/][this #+BEGIN_SRC elisp (cl-defun org-dblock-write:org-ql (params) "FIXME: Docstring" - (pcase-let* (((map :query :format :sort :ts-format) params) + (pcase-let* (((map :query :columns :sort :ts-format) params) (format-fns (list (cons 'heading (lambda (element) (org-make-link-string (org-element-property :raw-value element) (org-element-property :raw-value element)))) @@ -230,11 +230,11 @@ For example, [[https://egli.dev/posts/using-org-mode-for-meeting-minutes/][this :select '(org-element-headline-parser (line-end-position)) :order-by sort))) (cl-labels ((format-element - (element) (string-join (cl-loop for prop in format - for fn = (alist-get prop format-fns) + (element) (string-join (cl-loop for column in columns + for fn = (alist-get column format-fns) collect (funcall fn element)) " | "))) - (insert "| " (string-join (--map (capitalize (symbol-name it)) format) " | ") " |" "\n") + (insert "| " (string-join (--map (capitalize (symbol-name it)) columns) " | ") " |" "\n") (insert "|- \n") (dolist (element elements) (insert "| " (format-element element) " |" "\n")) diff --git a/org-ql-search.el b/org-ql-search.el index 1609d9e..c82d6f0 100644 --- a/org-ql-search.el +++ b/org-ql-search.el @@ -232,6 +232,81 @@ automatically from the query." ;;;###autoload (defalias 'org-ql-block 'org-ql-search-block) +;;;; Dynamic blocks + +;; This section implements support for Org dynamic blocks. See Info node `(org)Dynamic blocks'. + +(require 'org-table) + +(cl-defun org-dblock-write:org-ql (params) + "Insert content for org-ql dynamic block at point according to PARAMS. +Valid parameters include: + + :query An Org QL query expression in either sexp or non-sexp form. + + :columns A list of columns, including `heading', `todo', + `priority', `deadline', `scheduled'. + + :sort One or a list of Org QL sorting methods (see `org-ql-select'). + + :take Optionally take a number of results from the front (a + positive number) or the end (a negative number) of the results. + + :ts-format Optional format string used to format timestamp-based columns. + +For example, an org-ql dynamic block header could look like: + + #+BEGIN: org-ql :query (todo \"UNDERWAY\") :columns (priority todo heading) :sort (priority date) :ts-format \"%Y-%m-%d %H:%M\"" + (pcase-let* (((map :query :columns :sort :ts-format :take) params) + (query (cl-etypecase query + (string (org-ql--plain-query query)) + (t query))) + (columns (or columns '(heading todo priority))) + ;; MAYBE: Custom column functions. + (format-fns + ;; NOTE: Backquoting this alist prevents the lambdas from seeing + ;; the variable `ts-format', so we use `list' and `cons'. + (list (cons 'heading (lambda (element) + (org-make-link-string (org-element-property :raw-value element) + (org-element-property :raw-value element)))) + (cons 'todo (lambda (element) + (org-element-property :todo-keyword element))) + (cons 'priority (lambda (element) + (--when-let (org-element-property :priority element) + (char-to-string it)))) + (cons 'deadline (lambda (element) + (--when-let (org-element-property :deadline element) + (ts-format ts-format (ts-parse-org-element it))))) + (cons 'scheduled (lambda (element) + (--when-let (org-element-property :scheduled element) + (ts-format ts-format (ts-parse-org-element it))))))) + (elements (org-ql-query :from (current-buffer) + :where query + :select '(org-element-headline-parser (line-end-position)) + :order-by sort))) + (when take + (setf elements (cl-etypecase take + ((and integer (satisfies minusp)) (-take-last (abs take) elements)) + (integer (-take take elements))))) + (cl-labels ((format-element + (element) (string-join (cl-loop for column in columns + for fn = (alist-get column format-fns) + collect (or (funcall fn element) "")) + " | "))) + ;; Insert table header. + (insert "| " (string-join (--map (capitalize (symbol-name it)) + columns) + " | ") + " |" "\n") + ;; Separator line. + (insert "|- \n") + ;; Elements. + (dolist (element elements) + (insert "| " (format-element element) " |" "\n")) + ;; Delete final newline and align table. + (delete-char -1) + (org-table-align)))) + ;;;; Functions (cl-defun org-ql-search-directories-files (&key (directories (list org-directory)) diff --git a/org-ql.info b/org-ql.info index fea110e..afe4e3a 100644 --- a/org-ql.info +++ b/org-ql.info @@ -35,6 +35,7 @@ Usage * Commands:: * Queries:: * Functions / Macros:: +* Dynamic block:: * Tips:: Commands @@ -154,7 +155,7 @@ File: README.info, Node: Usage, Next: Changelog, Prev: Installation, Up: Top ******* • • - • • • • • • + • • • • • • • Feedback on these APIs is welcome. Eventually, after being tested and polished, they will be considered stable. @@ -165,6 +166,7 @@ and polished, they will be considered stable. * Commands:: * Queries:: * Functions / Macros:: +* Dynamic block:: * Tips::  @@ -544,7 +546,7 @@ number of days. The number can be negative to invert the direction. scheduled at any time.  -File: README.info, Node: Functions / Macros, Next: Tips, Prev: Queries, Up: Usage +File: README.info, Node: Functions / Macros, Next: Dynamic block, Prev: Queries, Up: Usage 4.3 Functions / Macros ====================== @@ -711,9 +713,49 @@ File: README.info, Node: Listing / acting-on results, Prev: Agenda-like views, For convenience, arguments should be unquoted.  -File: README.info, Node: Tips, Prev: Functions / Macros, Up: Usage +File: README.info, Node: Dynamic block, Next: Tips, Prev: Functions / Macros, Up: Usage -4.4 Tips +4.4 Dynamic block +================= + +Org QL provides a dynamic block that lists entries in the current +document matching a query. In the header, these parameters are +supported: + + • ‘:query’: An Org QL query expression in either sexp or non-sexp + form. + • ‘:columns’ A list of columns, including ‘heading’, ‘todo’, + ‘priority’, ‘deadline’, ‘scheduled’. + • ‘:sort’ One or a list of Org QL sorting methods (see + ‘org-ql-select’). + • ‘:take’ Optionally take a number of results from the front (a + positive number) or the end (a negative number) of the results. + • ‘:ts-format’ Optional format string used to format timestamp-based + columns. + + The heading column is formatted as a link to the heading (not shown +in the following example). + + For example, this dynamic block shows the first seven headings that +are to-do items with priority A or B, sorted by deadline then priority, +with certain columns and timestamp format: + + #+BEGIN: org-ql :query "todo: priority:A,B" :columns (todo priority deadline heading) :sort (deadline priority) :take 7 :ts-format "%Y-%m-%d %H:%M" + | Todo | Priority | Deadline | Heading | + |------+----------+------------------+---------------------------------------| + | TODO | A | 2017-07-07 00:00 | Take over the world | + | TODO | B | 2017-07-10 00:00 | Renew membership in supervillain club | + | TODO | A | 2017-07-15 00:00 | Take over the universe | + | TODO | B | 2017-07-21 00:00 | Internet | + | TODO | A | 2017-08-01 00:00 | Spaceship lease | + | TODO | A | | Skype with president of Antarctica | + | TODO | B | | Take over Mars | + #+END: + + +File: README.info, Node: Tips, Prev: Dynamic block, Up: Usage + +4.5 Tips ======== • Org QL View buffers can be bookmarked with Emacs bookmark commands, @@ -767,6 +809,7 @@ File: README.info, Node: 05-pre, Next: 046, Up: Changelog e.g. C-x r m and shown with, e.g. C-x r b. (This also enables view restoration with Burly (https://github.com/alphapapa/burly.el).) + • Dynamic block support. • Mascot. *Changed* @@ -1188,48 +1231,49 @@ GPLv3  Tag Table: Node: Top225 -Node: Contents1521 -Node: Screenshots1644 -Node: Installation1762 -Node: Quelpa2400 -Node: Usage2843 -Node: Commands3205 -Node: org-ql-search3678 -Node: helm-org-ql5392 -Node: org-ql-view5804 -Node: org-ql-view-sidebar6304 -Node: org-ql-view-recent-items6660 -Node: org-ql-sparse-tree7144 -Node: Queries7944 -Node: Non-sexp query syntax8852 -Node: General predicates10559 -Node: Ancestor/descendant predicates15774 -Node: Date/time predicates16902 -Node: Functions / Macros19557 -Node: Agenda-like views19803 -Node: Listing / acting-on results21208 -Node: Tips25810 -Node: Changelog26141 -Node: 05-pre26780 -Node: 04627626 -Node: 04528029 -Node: 04428388 -Node: 04328745 -Node: 04228940 -Node: 04129099 -Node: 0429338 -Node: 03233269 -Node: 03133646 -Node: 0333843 -Node: 02336818 -Node: 02237046 -Node: 02137314 -Node: 0237513 -Node: 0141548 -Node: Notes41649 -Node: Comparison with Org Agenda searches41811 -Node: org-sidebar42683 -Node: License42962 +Node: Contents1539 +Node: Screenshots1662 +Node: Installation1780 +Node: Quelpa2418 +Node: Usage2861 +Node: Commands3245 +Node: org-ql-search3718 +Node: helm-org-ql5432 +Node: org-ql-view5844 +Node: org-ql-view-sidebar6344 +Node: org-ql-view-recent-items6700 +Node: org-ql-sparse-tree7184 +Node: Queries7984 +Node: Non-sexp query syntax8892 +Node: General predicates10599 +Node: Ancestor/descendant predicates15814 +Node: Date/time predicates16942 +Node: Functions / Macros19597 +Node: Agenda-like views19852 +Node: Listing / acting-on results21257 +Node: Dynamic block25859 +Node: Tips27885 +Node: Changelog28211 +Node: 05-pre28850 +Node: 04629726 +Node: 04530129 +Node: 04430488 +Node: 04330845 +Node: 04231040 +Node: 04131199 +Node: 0431438 +Node: 03235369 +Node: 03135746 +Node: 0335943 +Node: 02338918 +Node: 02239146 +Node: 02139414 +Node: 0239613 +Node: 0143648 +Node: Notes43749 +Node: Comparison with Org Agenda searches43911 +Node: org-sidebar44783 +Node: License45062  End Tag Table