diff --git a/README.org b/README.org index 2a52476..59bbb23 100644 --- a/README.org +++ b/README.org @@ -69,6 +69,7 @@ Installing with [[https://framagit.org/steckerhalter/quelpa][Quelpa]] is easy: - [[#datetime-predicates][Date/time predicates]] - [[#functions--macros][Functions / Macros]] - [[#dynamic-block][Dynamic block]] +- [[#links][Links]] - [[#tips][Tips]] :END: @@ -427,6 +428,19 @@ For example, this dynamic block shows the first seven headings that are to-do it ,#+END: #+END_SRC +** Links + +Org QL View searches may be accessed by opening ~org-ql-search:~ links in an Org file. + +In an Org QL View buffer, the command ~org-store-link~ (i.e. ~C-c l~) stores a link to the current search, and it may be inserted into an Org buffer with the command ~org-insert-link~ (~C-c C-l~). The stored link records all of the view settings, like title, sorting, and grouping. + +Simple links may also be written manually in either sexp or non-sexp form, like: + +#+BEGIN_SRC org + [[org-ql-search:todo:NEXT priority:A]] + [[org-ql-search:(and (todo "NEXT") (priority "A"))]] +#+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]]. @@ -445,6 +459,7 @@ For example, this dynamic block shows the first seven headings that are to-do it + 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. ++ Org link support (storing and opening links to Org QL View searches in the current document). + Mascot. *Changed* diff --git a/notes.org b/notes.org index d9f2ae9..78d8c32 100644 --- a/notes.org +++ b/notes.org @@ -16,12 +16,15 @@ * [#A] Overview +** Underway + +[[org-ql-search:%2528todo%2520%2522UNDERWAY%2522%2529?sort=%2528priority%2529&title=%2522Underway%2522][org-ql-search: Underway]] + #+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]] | | A | UNDERWAY | [[Tools%20for%20saving%20queries%20and%20accessing%20them%20%5B3/4%5D][Tools for saving queries and accessing them {3/4}]] | -| A | UNDERWAY | [[Org link types][Org link types]] | +| A | UNDERWAY | [[Org%20link%20types%20%5B2/3%5D][Org link types {2/3}]] | | A | UNDERWAY | [[Outline path predicate][Outline path predicate]] | | B | UNDERWAY | [[Recursive queries][Recursive queries]] | | B | UNDERWAY | [[Timeline view][Timeline view]] | @@ -30,6 +33,19 @@ | | UNDERWAY | [[Benchmarking tags searches without and with new group-tags support][Benchmarking tags searches without and with new group-tags support]] | #+END: +** To-do + +[[org-ql-search:%2528and%2520%2528todo%2520%2522TODO%2522%2529%2520%2528priority%2520%2522A%2522%2529%2529?sort=%2528priority%2529&title=%2522To-do%2520%255B%2523A%255D%2522][org-ql-search: To-do {#A}]] + +#+BEGIN: org-ql :query "todo:TODO priority:A" :columns (priority todo heading) :sort (priority date) :take 7 +| Priority | Todo | Heading | +|----------+------+--------------------------------------------------------------| +| A | TODO | [[Add ~:auto~ keyword to ~(planning)~ predicate][Add ~:auto~ keyword to ~(planning)~ predicate]] | +| A | TODO | [[Document sorters][Document sorters]] | +| A | TODO | [[Org block to insert results of queries with links to entries][Org block to insert results of queries with links to entries]] | +| A | TODO | [[Change ~(deadline)~'s ~auto~ argument to ~:auto~ and/or ~:auto t~][Change ~(deadline)~'s ~auto~ argument to ~:auto~ and/or ~:auto t~]] | +#+END: + * [#A] Tasks :PROPERTIES: :TOC: :include descendants :depth 1 @@ -49,7 +65,6 @@ - [[#org-agenda-skip-function][org-agenda-skip-function]] - [[#test-caching][Test caching]] - [[#update-commentary][Update commentary]] -- [[#dynamic-blocks][Dynamic blocks]] - [[#tools-for-saving-queries-and-accessing-them-34][Tools for saving queries and accessing them {3/4}]] - [[#outline-path-predicate][Outline path predicate]] - [[#recursive-queries][Recursive queries]] @@ -60,6 +75,7 @@ - [[#alternative-parsing-libraries][Alternative parsing libraries]] - [[#fancier-searching-for-inherited-tags][Fancier searching for inherited tags]] - [[#group-tag-support][Group tag support]] +- [[#dynamic-blocks][Dynamic blocks]] - [[#helm-command][Helm command]] - [[#quickly-change-sortinggrouping-in-search-views][Quickly change sorting/grouping in search views]] - [[#byte-compile-lambdas][Byte-compile lambdas]] @@ -194,13 +210,17 @@ See notes on 1dce9467f25428b5289d3665cd840820969ed65a. It would be good to test + Added example to =examples.org=. -*** UNDERWAY [#A] Org link types +*** UNDERWAY [#A] Org link types [2/3] :PROPERTIES: :ID: 4db73c1c-a4ed-425e-9e38-8d334ed03e1e :END: This would be useful for having a menu of saved queries as Org links, or even bookmarking saved queries. +**** TODO For saved queries + +**** DONE For searches + [2020-11-08 Sun 22:59] Let's try a very simple implementation so I could write a link like this to search the current buffer: #+BEGIN_SRC org @@ -209,7 +229,7 @@ This would be useful for having a menu of saved queries as Org links, or even bo [2020-11-08 Sun 23:22] Seems to work! -#+BEGIN_SRC elisp +#+BEGIN_SRC elisp :results silent ;;;; Org link type ;; This section adds a custom link type to Org. See info:org#Adding hyperlink types. @@ -240,9 +260,103 @@ Tested on these queries: + [[org-ql-search:link:nullprogram]] #+END_SRC -**** TODO For all parameters +[2020-11-10 Tue 00:35] I'd like to support other parameters to the search, like grouping and sorting, so: -**** TODO For saved queries +#+BEGIN_SRC elisp :results silent + ;;;; Org link type + + ;; This section adds a custom link type to Org. See info:org#Adding hyperlink types. + + (org-link-set-parameters "org-ql-search" + :follow #'org-ql-search--link-open + :store #'org-ql-search--link-store) + + (defun org-ql-search--link-open (query) + "Open Org QL QUERY for current buffer." + (require 'url-parse) + (pcase-let* ((`(,query . ,params) + (url-path-and-query (url-parse-make-urlobj "org-ql-search" nil nil nil nil + query))) + (params (url-parse-query-string params)) + ;; Hacky or elegant? + (_ (mapc (lambda (pair) + (cl-callf (lambda (it) + (intern (concat ":" it))) + (car pair)) + (cl-callf read (cdr pair))) + params)) + (params (cl-loop for (key . value) in params + append (list key value)))) + (apply #'org-ql-search (current-buffer) query params))) + + (defun org-ql-search--link-store () + "Store a link to current Org QL query." + (when org-ql-view-query + (org-store-link-props :type "org-ql-search" + :link (concat "org-ql-search:" (org-ql-view--format-query org-ql-view-query)) + :description org-ql-view-title) + t)) +#+END_SRC + +That seems to work, like: + +#+BEGIN_SRC org + [[org-ql-search:property:author="Chris%20Wellons"?super-groups=((:auto-outline-path%20t))]] +#+END_SRC + +[2020-11-10 Tue 01:34] Okay, this seems to take care of all parameters: + +#+BEGIN_SRC elisp + (defun org-ql-search--link-open (path) + "Open Org QL query for current buffer at PATH. + PATH should be the part of an \"org-ql-search:\" URL after the + protocol. See, e.g. `org-ql-search--link-store'." + (require 'url-parse) + (require 'url-util) + (pcase-let* ((`(,query . ,params) (url-path-and-query + (url-parse-make-urlobj "org-ql-search" nil nil nil nil + path))) + (query (url-unhex-string query)) + (params (when params + (url-parse-query-string params))) + ;; `url-parse-query-string' returns "improper" alists, which makes this awkward. + (sort (when (alist-get "sort" params nil nil #'string=) + (read (alist-get "sort" params nil nil #'string=)))) + (groups (when (alist-get "super-groups" params nil nil #'string=) + (read (alist-get "super-groups" params nil nil #'string=)))) + (title (when (alist-get "title" params nil nil #'string=) + (read (alist-get "title" params nil nil #'string=))))) + (org-ql-search (current-buffer) query + :sort sort + :super-groups groups + :title title))) + + (defun org-ql-search--link-store () + "Store a link to the current Org QL view. + Only views that search a single buffer may be linked to." + (require 'url-parse) + (require 'url-util) + (unless (or (bufferp org-ql-view-buffers-files) (= 1 (length org-ql-view-buffers-files))) + (user-error "Only views searching a single buffer may be linked")) + (when org-ql-view-query + (let* ((params (list (when org-ql-view-super-groups + (list "super-groups" (prin1-to-string org-ql-view-super-groups))) + (when org-ql-view-sort + (list "sort" (prin1-to-string org-ql-view-sort))) + (when org-ql-view-title + (list "title" (prin1-to-string org-ql-view-title))))) + (filename (concat (url-hexify-string (org-ql-view--format-query org-ql-view-query)) + "?" (url-build-query-string (delete nil params)))) + (url (url-recreate-url (url-parse-make-urlobj "org-ql-search" nil nil nil nil + filename)))) + (org-store-link-props + :type "org-ql-search" + :link url + :description (concat "org-ql-search: " org-ql-view-title))) + t)) +#+END_SRC + +**** DONE For all parameters *** DONE Bookmarks diff --git a/org-ql-view.el b/org-ql-view.el index 30be96d..676b6c0 100644 --- a/org-ql-view.el +++ b/org-ql-view.el @@ -565,6 +565,68 @@ dates in the past, and negative for dates in the future." ;; more complicated and might introduce bugs elsewhere, so we'll just do this for now. (set-buffer (window-buffer (selected-window))))) +;;;; Links + +;; This section implements support for Org links to Org QL searches. Since the +;; links are stored from and opened in `org-ql-view' buffers, this section resides +;; in this file. However, since the links are to `org-ql-search' searches rather +;; than `org-ql-view' saved views, the link type is "org-ql-search". + +(org-link-set-parameters "org-ql-search" + :follow #'org-ql-view--link-open + :store #'org-ql-view--link-store) + +;; We require the URL libraries in the functions to hopefully avoid +;; loading them until they're needed. + +(defun org-ql-view--link-open (path) + "Open Org QL query for current buffer at PATH. +PATH should be the part of an \"org-ql-search:\" URL after the +protocol. See, e.g. `org-ql-view--link-store'." + (require 'url-parse) + (require 'url-util) + (pcase-let* ((`(,query . ,params) (url-path-and-query + (url-parse-make-urlobj "org-ql-search" nil nil nil nil + path))) + (query (url-unhex-string query)) + (params (when params (url-parse-query-string params))) + ;; `url-parse-query-string' returns "improper" alists, which makes this awkward. + (sort (--when-let (alist-get "sort" params nil nil #'string=) + (read it))) + (groups (--when-let (alist-get "super-groups" params nil nil #'string=) + (read it))) + (title (--when-let (alist-get "title" params nil nil #'string=) + (read it)))) + (org-ql-search (current-buffer) query + :sort sort + :super-groups groups + :title title))) + +(defun org-ql-view--link-store () + "Store a link to the current Org QL view. +When opened, the link searches the buffer it's opened from." + (require 'url-parse) + (require 'url-util) + (unless (or (bufferp org-ql-view-buffers-files) + (= 1 (length org-ql-view-buffers-files))) + (user-error "Only views searching a single buffer may be linked")) + (when org-ql-view-query + (let* ((params (list (when org-ql-view-super-groups + (list "super-groups" (prin1-to-string org-ql-view-super-groups))) + (when org-ql-view-sort + (list "sort" (prin1-to-string org-ql-view-sort))) + (when org-ql-view-title + (list "title" (prin1-to-string org-ql-view-title))))) + (filename (concat (url-hexify-string (org-ql-view--format-query org-ql-view-query)) + "?" (url-build-query-string (delete nil params)))) + (url (url-recreate-url (url-parse-make-urlobj "org-ql-search" nil nil nil nil + filename)))) + (org-store-link-props + :type "org-ql-search" + :link url + :description (concat "org-ql-search: " org-ql-view-title))) + t)) + ;;;; Transient ;; This section uses `transient' to allow the user to easily modify diff --git a/org-ql.info b/org-ql.info index afe4e3a..e54d655 100644 --- a/org-ql.info +++ b/org-ql.info @@ -36,6 +36,7 @@ Usage * Queries:: * Functions / Macros:: * Dynamic block:: +* Links:: * Tips:: Commands @@ -155,7 +156,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. @@ -167,6 +168,7 @@ and polished, they will be considered stable. * Queries:: * Functions / Macros:: * Dynamic block:: +* Links:: * Tips::  @@ -713,7 +715,7 @@ File: README.info, Node: Listing / acting-on results, Prev: Agenda-like views, For convenience, arguments should be unquoted.  -File: README.info, Node: Dynamic block, Next: Tips, Prev: Functions / Macros, Up: Usage +File: README.info, Node: Dynamic block, Next: Links, Prev: Functions / Macros, Up: Usage 4.4 Dynamic block ================= @@ -753,9 +755,30 @@ with certain columns and timestamp format: #+END:  -File: README.info, Node: Tips, Prev: Dynamic block, Up: Usage +File: README.info, Node: Links, Next: Tips, Prev: Dynamic block, Up: Usage -4.5 Tips +4.5 Links +========= + +Org QL View searches may be accessed by opening ‘org-ql-search:’ links +in an Org file. + + In an Org QL View buffer, the command ‘org-store-link’ (i.e. ‘C-c +l’) stores a link to the current search, and it may be inserted into an +Org buffer with the command ‘org-insert-link’ (‘C-c C-l’). The stored +link records all of the view settings, like title, sorting, and +grouping. + + Simple links may also be written manually in either sexp or non-sexp +form, like: + + [[org-ql-search:todo:NEXT priority:A]] + [[org-ql-search:(and (todo "NEXT") (priority "A"))]] + + +File: README.info, Node: Tips, Prev: Links, Up: Usage + +4.6 Tips ======== • Org QL View buffers can be bookmarked with Emacs bookmark commands, @@ -810,6 +833,8 @@ File: README.info, Node: 05-pre, Next: 046, Up: Changelog view restoration with Burly (https://github.com/alphapapa/burly.el).) • Dynamic block support. + • Org link support (storing and opening links to Org QL View searches + in the current document). • Mascot. *Changed* @@ -1231,49 +1256,50 @@ GPLv3  Tag Table: Node: Top225 -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 +Node: Contents1549 +Node: Screenshots1672 +Node: Installation1790 +Node: Quelpa2428 +Node: Usage2871 +Node: Commands3269 +Node: org-ql-search3742 +Node: helm-org-ql5456 +Node: org-ql-view5868 +Node: org-ql-view-sidebar6368 +Node: org-ql-view-recent-items6724 +Node: org-ql-sparse-tree7208 +Node: Queries8008 +Node: Non-sexp query syntax8916 +Node: General predicates10623 +Node: Ancestor/descendant predicates15838 +Node: Date/time predicates16966 +Node: Functions / Macros19621 +Node: Agenda-like views19876 +Node: Listing / acting-on results21281 +Node: Dynamic block25883 +Node: Links27910 +Node: Tips28597 +Node: Changelog28915 +Node: 05-pre29554 +Node: 04630536 +Node: 04530939 +Node: 04431298 +Node: 04331655 +Node: 04231850 +Node: 04132009 +Node: 0432248 +Node: 03236179 +Node: 03136556 +Node: 0336753 +Node: 02339728 +Node: 02239956 +Node: 02140224 +Node: 0240423 +Node: 0144458 +Node: Notes44559 +Node: Comparison with Org Agenda searches44721 +Node: org-sidebar45593 +Node: License45872  End Tag Table